← Back to Writeups
CUSTOMEasyForensics

CTF-er, который смог (The CTF-er Who Could)

XESXOR9/2/20263 min read
#forensics#custom#easy#crc32_verification#data_descriptor_anchor#raw_deflate_decompression#zip_carving

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 signature PK\x03\x04 (50 4B 03 04) is expected.
  • The only valid PK signature anywhere in the file is PK\x07\x08 (data descriptor) at offset 0x3de4d (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 ux extra field (75 78 0b 00 01 04 00000000 04 00000000) — UID/GID extra, length 0x000b = 11.
  • At offset 18: a UT extra field (55 54 0d 00 07 + three 4-byte timestamps) — extended timestamp, length 0x000d = 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
#!/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. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍