CTF-er, который смог (The CTF-er Who Could)
CTF-er, который смог (The CTF-er Who Could)
Platform: bug-makers | Category: Forensics | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-05-29 | Status: Solved Techniques: crc32_verification, data_descriptor_anchor, raw_deflate_decompression, zip_carving
Summary
Task: a 253531-byte file 'Bubba' with a corrupted ZIP local header and stripped central directory/EOCD. Solution: locate the deflate stream offset via surviving ux/UT extra fields and the trailing PK0708 data descriptor, then raw-deflate decompress to recover a JPEG containing the flag.
CTF-er, который смог — bug-makers
Description
«— Пейн, я не чувствую центральной директории! — Буба, у тебя ее нет!»
(Translation: "— Payne, I don't feel the central directory! — Bubba, you don't have one!")
The challenge name "CTF-ер, который смог" ("The CTF-er who could") is a pun on the Russian dub of The Little Engine That Could and the movie Major Payne. The dialogue is adapted from Major Payne. The provided artifact was a 253531-byte file named Bubba that file identifies only as data. The semantic hint "central directory" points directly at a ZIP archive with a missing/corrupted central directory.
Analysis
The file is a damaged ZIP. Hexdump analysis revealed:
- The file begins with corrupted bytes
66 69 66 75(fifu) where the ZIP local file header signaturePK\x03\x04(50 4B 03 04) is expected. - The only valid PK signature anywhere in the file is
PK\x07\x08(data descriptor) at offset0x3de4d(253517). - There is no central directory record (
PK\x01\x02) and no End Of Central Directory (PK\x05\x06) — exactly matching the "central directory" hint.
Despite the corrupted header, the ZIP structure remnants survive:
- At offset 3: an Info-ZIP
uxextra field (75 78 0b 00 01 04 00000000 04 00000000) — UID/GID extra, length0x000b= 11. - At offset 18: a
UTextra field (55 54 0d 00 07+ three 4-byte timestamps) — extended timestamp, length0x000d= 13. - The extra field block spans offsets 3..34 (32 bytes), so the deflate-compressed data stream begins at offset 35.
The truncated data descriptor at offset 253517 leaks the values needed for recovery:
PK\x07\x08+ crc32 =0xad1a85b7+ compressed_size =0x0003de2a= 253482.- The compressed region from offset 35 to the data descriptor is exactly 253482 bytes — matching the csize in the descriptor.
Solution
Rebuilding the ZIP is unnecessary. Once the deflate stream offset (35) is located via the surviving ux/UT extra fields, and the trailing data descriptor confirms the compressed size and CRC32, the payload can be recovered with a direct raw-deflate decompression.
python read-only • copy allowed#!/usr/bin/env python3 import zlib data = open('Bubba', 'rb').read() # The data descriptor is a reliable anchor: it stores crc32 + compressed size dd_off = data.find(b'PK\x07\x08') # Deflate stream begins at offset 35 (after corrupted header + ux/UT extra fields) comp = data[35:dd_off] # Raw deflate (no zlib header) -> window bits -15 out = zlib.decompress(comp, -15) open('recovered.jpg', 'wb').write(out) print('decompressed:', len(out)) # 259623 # Verify against the CRC32 leaked in the data descriptor crc = zlib.crc32(out) & 0xffffffff print('crc32:', hex(crc)) # 0xad1a85b7 (matches descriptor) assert crc == 0xad1a85b7
The output is a 259623-byte JPEG (1200x900) of Major Payne in a US Marines uniform with the name tag "PAYNE". The top caption reads "Зато есть флаг" ("But there is a flag"), and the flag is printed in plaintext at the bottom of the image.