← Back to Writeups
CUSTOMEasyMisc

Пазл из 2500 кусочков

XESXOR9/2/20262 min read
#misc#custom#easy#image_grid_reassembly_from_num

Пазл из 2500 кусочков

Platform: bug-makers | Category: Misc | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-05-25 | Status: Solved Techniques: image_grid_reassembly_from_numbered_tiles

Summary

Task: a 600x600 image was cut into 2500 equal 12x12 pixel pieces numbered sequentially. Solution: reassemble the grid using PIL by placing each piece at its (col, row) position computed from its index.

Пазл из 2500 кусочков — Bug Makers CTF

Description

Исходную картинку, где написан флаг, разрезали на 2500 равных частей. Чтобы прочитать флаг, нужно собрать все на место. Части пазлов пронумерованы слева направо и сверху вниз. Исходное изображение имеет размер 600х600 пикселей.

English summary: The original 600×600 pixel image containing the flag was cut into 2500 equal pieces. Pieces are numbered left-to-right, top-to-bottom. Reassemble them to read the flag. Attachment: 2500-puzzles-flag.zip. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Analysis

The ZIP archive contains 2500 PNG files named 1.png through 2500.png. Each piece is 12×12 pixels (RGBA PNG).

Key calculations:

  • Image size: 600×600 pixels
  • Number of pieces: 2500
  • √2500 = 50 → grid is 50×50
  • Piece size: 600 / 50 = 12×12 pixels ✓

The numbering scheme is straightforward sequential ordering:

  • Piece i (1-indexed) maps to grid position (col, row) where:
    • col = (i - 1) % 50
    • row = (i - 1) // 50
  • Pixel offset: (col * 12, row * 12)

Solution

A simple Python script using PIL reassembles the image by placing each numbered piece at its computed grid position. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

python
#!/usr/bin/env python3
from PIL import Image

GRID = 50        # 50x50 grid
PIECE_SIZE = 12  # each piece is 12x12 pixels
IMG_SIZE = 600   # 600x600 output image

result = Image.new('RGBA', (IMG_SIZE, IMG_SIZE))

pieces_dir = "pieces/2500-puzzles-flag"

for i in range(1, 2501):
    idx = i - 1
    col = idx % GRID
    row = idx // GRID
    
    piece = Image.open(f"{pieces_dir}/{i}.png")
    result.paste(piece, (col * PIECE_SIZE, row * PIECE_SIZE))

result.save("assembled.png")
print("Image assembled successfully!")

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The assembled image shows a ladybug cartoon holding a red "CTF" flag, with the flag text written at the bottom. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍