Broken Piece

0xFun CTFby smothy

Broken Piece - Misc

Points: 275 | Flag: 0xfun{br0k3n_qr_r3c0v3rd} | Solved by: Smothy @ 0xN1umb

puzzle time

what we got

secret_id.png - a creepy zombie ID card image (1536x1024). two QR codes on it:

  • top-right: partial QR code on white background, torn paper effect rips off the upper-right corner
  • bottom-right: smaller QR with a skull overlay, decorative/unusable

challenge literally says "recover the QR code since it seems broken" - ok bet

the solve

first tried scanning both QR codes directly with zbarimg - nothing. both too damaged. the bottom-right skull one is decorative garbage, so focused on the top-right QR.

step 1: find the QR structure

used the 1:1:3:1:1 ratio detection to locate finder patterns. QR codes have 3 finder patterns (the big squares in the corners) - the top-right one was completely missing due to the torn paper

Top-left finder center: y=119, widths=[10,9,28,9,10], module~9.4px Bottom-left finder center: y=289, widths=[9,9,28,10,9], module~9.3px Distance between centers: 170px

170px / 18 modules = 9.44px per module. that makes it QR Version 2 (25x25 modules)

step 2: extract the module grid

sampled each of the 625 modules from the original image. the torn paper area had gray/brown pixels (~140-180 value) vs QR black (<80) and white (>220), so easy to classify:

Black: 277, White: 287, Unknown: 61 (9.8% missing)

only 9.8% missing - well within QR error correction limits (up to 30% for level H)

step 3: reconstruct the missing patterns

added back the known QR structures that were in the torn area:

  • top-right finder pattern (7x7) at rows 0-6, cols 18-24
  • separator patterns (white borders around finders)
  • timing patterns (alternating B/W on row 6 and col 6)
  • alignment pattern (5x5) at position (18,18) for version 2
  • filled remaining unknowns with white
python
# the key part - adding the missing finder
finder = np.array([
    [1,1,1,1,1,1,1],
    [1,0,0,0,0,0,1],
    [1,0,1,1,1,0,1],
    [1,0,1,1,1,0,1],
    [1,0,1,1,1,0,1],
    [1,0,0,0,0,0,1],
    [1,1,1,1,1,1,1]
])
grid[0:7, 18:25] = finder  # top-right finder restored!

rendered the grid to a clean PNG at 10x scale with quiet zone margins

step 4: decode

$ zbarimg --raw qr_reconstructed.png 0xfun{br0k3n_qr_r3c0v3rd}

first try lets gooo

flag

0xfun{br0k3n_qr_r3c0v3rd}

broken qr recovered - literally what we did lol. the key insight is understanding QR code structure: once you know the finder pattern positions and module size, you can reconstruct the missing parts. QR error correction handles the rest. medium difficulty is fair - you need to know QR internals but its not rocket science


smothy out ✌️