RowdyHacks XII: sonion

A 250-point forensics-into-reversing challenge: carving a ZIP from a PNG, then inverting a 46-byte checker's per-byte transform to recover the accepted code.

RowdyHacks XII

forensics250 ptsfile-carvingreverse-engineeringpngchecker-inversion

Challenge

Forensics · 250 points. A meme image, sonion.png, is provided.

Carve the payload

pngcheck -v reports data after the PNG's IEND chunk. At offset 0x37c93 that trailing data begins with a ZIP header. The carved archive holds order.txt, a README.txt, and a stripped Linux executable receipt_check. The README says the code the program accepts is the flag.

Invert the checker

receipt_check wants a 46-byte input and compares each transformed byte against a table in the binary. The transform (helper at 0x401955) is:

out[i] = ROL8( ((input[i] ^ 0x5a) + 7*i) & 0xff, 3 )

Every step is reversible, so recovering the input is mechanical: undo the rotate, subtract 7*i, XOR with 0x5a, for each of the 46 positions:

input[i] = (ROR8(table[i], 3) - 7*i) ^ 0x5a

Feeding the recovered string back in, the checker responds receipt accepted, and that string is the flag.

Takeaway

Two familiar primitives stack: data after the PNG's IEND is carvable, and a verification routine shipped inside a binary is reversible no matter how many XOR and rotate steps it uses. Validate and re-encode uploads to kill the carve, and never treat a client-side check as a secret, since anything the client computes an attacker computes backwards.

Flag

Spoiler: show the flag
rowdy{when_you_find_an_onion_ring_in_yo_fries}