zwesty
Write-ups / Day 16 / Metadata
Day 16 · Fri, Oct 16 · Metadata

Return to Sender

Prey slaughtered

Email headers (RFC 5322 Message-ID), exact-text answers, pre-built parsers

STTMClaude Homebase Both

Flags are shortened to their first 8 and last 4 characters because they're unique per team.

Challenge ID
metadata-forensics-day-16-return-to-sender (+ /time_trial, /mastery)
Solved
2026-10-16, all three modes, 34 s from the first start (13:00:10 → 13:00:44 UTC)
Player
Zwesty (solo), with Claude Code (Opus 5.5): our automated morning solver (a scheduled script on our Kali VM) and a parser pre-built the day before

The challenge

A mailbox export contains replies, forwards, duplicates, and reconstructed messages. Use stable message identities to rebuild which mail actually belongs together.

Single Solve: one question, "Determine email.message_id for message-001.eml", as the exact artifact-derived text (none only if the header is missing). The timed modes ask the same field, and every earlier day's fields, over many files.

Reading the prompt: what it said we'd need

Clue What it pointed to What I did about it
"mailbox export", "replies, forwards, duplicates" .eml files and their threading headers The pre-built mail parser reads Message-ID, In-Reply-To, References
"stable message identities" The Message-ID header, the one value that survives forwarding and re-export Answer the header as stored
email.message_id, "exact artifact-derived value" Text as written in the file Sent verbatim, angle brackets included

What was in the files

Single Solve: a 602-byte zip holding message-001.eml (783 bytes): plain headers (From, To, Subject, Date, Message-ID) at example.test addresses and a short body. Time Trial: a 607 KB evidence zip; Mastery: a 3 MB zip with many sets mixing this field with earlier days' file types.

Single Solve

The morning solver sorted the one question as pre-built: email-message-id was among the ~11,000 field names we had pre-built parsers for the day before. With every question either known or pre-built, the solver sends the Single Solve itself. The answer was the header value exactly as stored, <…@example.test>, brackets included (Day 13's lesson: send text fields verbatim).

start 487 ms · artifact 390 ms · solve 1 ms · submit 1000 ms · TOTAL 1878 ms
result CORRECT  flag ba34cb4a…fab1

Then a regression rehearsal: 67 saved attempts, slowest 0.13 s, per-set answers identical. It passed.

Time Trial and Mastery

Both ranked, straight after the rehearsal.

Time Trial: 21 answers · start 630 ms · artifact 569 ms · solve 23 ms · submit 1351 ms · TOTAL 2573 ms
result CORRECT  flag cd486836…9555

Mastery: 105 answers · start 687 ms · artifact 875 ms · solve 544 ms · submit 1174 ms · TOTAL 3279 ms
result CORRECT  flag 767579ab…4a96

Time to solve

All three modes were solved by 13:00:44 UTC (09:00:44 ET), 34 s after the first start, each on the first submit. The ranked Time Trial and Mastery took 2 s and 3 s on the clock.

Takeaways

  • The pre-build paid off completely: the new field was answered by a parser written the day before, so the lane was done 44 s after release with nobody touching it.
  • Verbatim again: the Message-ID went in with its angle brackets, as stored; no normalising.