← Z0D1AK writeups
Forensics ✓ independently re-verified

BLACKBOX

Reverse-engineering an undocumented 16-byte binary telemetry record format.

Flag`zdk{e1EMeNt4RY_81naRY_P4rSlNg_MA573R}`

Flag: zdk{e1EMeNt4RY_81naRY_P4rSlNg_MA573R}

TL;DR

A drone's "flight recorder" dump is a flat array of fixed-size 16-byte records spanning three record types. Two types are smooth decoy telemetry; the rare, self-labeled "impact" records carry the flag, XORed with a key that is hiding in plain sight as their own trailer bytes.

Challenge

Recover the flag from blackbox.bin (3920 bytes), a drone flight recorder dump that standard forensics tools report as undocumented raw binary. Delivered both loose and inside black-box.zip (identical MD5 — the zip is just a delivery wrapper, not part of the puzzle).

Step 1 — Identify the record structure

file reports plain data; strings turns up nothing relevant. A hex dump reveals a repeating 42 58 ("BX") magic every 16 bytes:

3920 bytes / 16 = 245 records, no remainder → fixed-size record array

Per-record layout: BX | type(1B) | 00 00 | seq(1B) | payload(9B) | ...

Step 2 — Classify records by type

A small parser (parse_bb.py) buckets records by the type byte (offset 2):

Type Count Behavior
0x01 120 Steadily incrementing counter — decoy sensor channel
0x02 120 Steadily incrementing/decrementing counter — decoy sensor channel
0x03 5 Sparse; every record ends in DE AD — the "impact" marker

The 240 type 0x01/0x02 records are smooth, monotonic telemetry (altitude/ orientation-style counters) — a distraction. The five type 0x03 records are the tell: the challenge framing says the recorder "suffered during impact," and these are the only records literally trailed with DE AD.

Step 3 — Decode the payloads

Each type 0x03 record's 8-byte payload, XORed with a repeating 2-byte key DE AD, produces clean ASCII. The key is the same DE AD bytes already visible as every record's trailer:

key = bytes.fromhex("deaddeaddeaddead")
dec = bytes(b ^ k for b, k in zip(payload, key))

Step 4 — Reassemble in sequence order

Sorting the five type 0x03 records by their internal sequence byte (offset 5, values 0–4) and concatenating the decoded payloads:

seq decoded
0 zdk{e1EM
1 eNt4RY_8
2 1naRY_P4
3 rSlNg_MA
4 573R} (+ null padding)

Flag

zdk{e1EMeNt4RY_81naRY_P4rSlNg_MA573R}

(leetspeak for "elementary binary parsing master")

Key hints that led here

  1. Fixed 16-byte record size with a clean division (3920/16) signals a structured format, not garbage.
  2. BX magic + type byte → multiple record "channels" multiplexed together.
  3. Type 0x01/0x02 are arithmetic-progression red herrings.
  4. Type 0x03 is rare and self-labeled with DE AD, matching the crash/impact framing in the challenge description.
  5. The trailer bytes double as the XOR key — a common "the key sits right next to the ciphertext" CTF trick.

Tools & Files

Takeaway

When a binary dump divides cleanly into a fixed record size, stop guessing at file formats and start bucketing by a byte that looks like a type/tag field — the outlier bucket is almost always where the signal lives.

Solve scripts:
parse_bb.pydecode_bb.py