online
writeups

Qrecreate

utctf2026 misc

Pasted image 20260314050434

The challenge provides 100 directories, each containing a data/img.png file. The directory names look like Base64-encoded values, so the first step is to decode them. Once decoded, they map cleanly to values from 001 to 100, which gives the correct order of the image fragments. I then copied each img.png out of its directory and renamed it with its decoded numeric values.

Pasted image 20260314051356

Pasted image 20260314053609

Pasted image 20260314053640

for dir in [0-9]*/; do                          venv 3.14.3  05:51 
    cp "$dir/data/img.png" "${dir%/}.png"
done

Pasted image 20260314055206

Each fragment is 74x74 pixels, and there are 100 fragments in total, which strongly suggests a 10x10 layout. I wrote a short Python script with PIL to rebuild the full image by placing the tiles in order from 001 to 100, row by row. This produced a final 740x740 image called output.png.

from PIL import Image
import os

##  Grid 10X10, each size is 74X74, so final image size of 740x740 ?

## To remap each square into the grid,
# Check in which row to place it, Value // 10
# Check in which col to place it, Value % 10

Result = Image.new("RGB", (740, 740)) ## Create blank image.
getdirs = os.listdir()
dic = {}
for dir in getdirs:
    if ".png" not in dir:
        continue
    pos = int(dir.strip("qr_").strip(".png"))
    dic[pos] = dir

for i in range(1 ,101):
    y = (i - 1) // 10
    x = (i - 1) % 10

    Tmp = Image.open(f"./{dic[i]}")
    Result.paste(Tmp, (x*74, y*74))
    
Result.show()
Result.save("output.png")

Pasted image 20260314071110

The reconstructed image is a QR code. Reading it with zbarimg output.png returns a long Lorem Ipsum text, but the important part is the suspicious Base64 string embedded in that output. Extracting that Base64 value and decoding it reveals the flag.

Pasted image 20260314071151

Pasted image 20260314071232

● NORMAL 0xBlog
JetBrains Mono UTF-8 Hugo