zwesty
Write-ups / Day 19 / Binary
Day 19 · Mon, Oct 19 · Binary

Jack in the Box

Prey slaughtered

Static ELF inspection, archive handling, overlay decoding, SHA-256 and CRC32 validation, JSON parsing

STTMClaude Homebase Both

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

Challenge ID
binary-reverse-engineering-day-19-static-unpacking; Time Trial: /time_trial; Mastery: /mastery
Solved
2026-10-19; all three modes. 10 min 36 s from the first start (our automated morning solver, a scheduled script on our Kali VM, 13:00:34 UTC) to the last CORRECT (the Homebase agent, Mastery, 13:11:10 UTC).
Player
Zwesty (solo), with Claude Code (Opus 5.5) and the Homebase agent (GPT-6 Luna). Our automated morning solver sent the fields earlier days already covered; the Homebase agent solved the new Day 19 fields and ran both timed modes

The challenge

There's a payload hiding inside this binary, and a little decoder stub wound up to pop it out. Find the stub, watch it work, and catch what's inside — statically.

The challenge supplied 228 answer fields across Day 1–19 in evidence.zip. Each field had an exact API answer_id, with its own question wording, artifact reference, normalization rule, and answer format.

The Day 19 fields asked for the ELF's artifact hash, architecture, and format, plus configuration and overlay properties:

answer_id Question Format
d19_artifact_sha256_1 Hash the first d19-- member in ZIP central-directory order. Exactly 64 lowercase hexadecimal characters.
d19_analysis_architecture, d19_analysis_machine Identify the processor architecture from the executable header / machine field. Architecture or standard tool label, or accepted machine code.
d19_analysis_format Classify the final bytes and parsed container. One exact lowercase enum: elf, pe, pe_cli, jar, wasm, or neko_bytecode.
d19_analysis_config_campaign Decode HCFG and submit config.campaign. Exact case-sensitive text, without quotes.
d19_analysis_config_domain Decode HCFG and submit config.domain. Exact case-sensitive text, without quotes.
d19_analysis_config_mutex Decode HCFG and submit config.mutex. Exact case-sensitive text, without quotes.
d19_analysis_config_url Decode HCFG and submit config.url. Exact case-sensitive text, without quotes.
d19_analysis_config_crc32_hex Read the decoded HCFG payload CRC32. 0x followed by eight lowercase hexadecimal digits.
d19_analysis_hcfg_version Read HCFG header byte 4. Unsigned base-10 integer.
d19_analysis_overlay_offset Locate the final PK19 magic in the member. Zero-based byte offset, base-10 integer.
d19_analysis_overlay_size Subtract the overlay offset from the member byte length. Base-10 integer.

Reading the prompt: what it said we'd need

Clue What it pointed to What I did about it
“payload hiding inside this binary” A structured record was embedded in an executable. Inspected the assigned ELF bytes and located the final PK19 overlay.
“a little decoder stub” The payload had a reversible transform whose parameters were stored beside it. Read the overlay keys and length from its header, then reversed the byte transform statically.
“watch it work” The transform needed validation before its output could be trusted. Checked the decoded SHA-256, then decoded HCFG and checked its CRC32 before parsing JSON. No binary was executed.
“catch what's inside” The useful answers were fields from the recovered configuration. Submitted the exact campaign, domain, mutex, and URL strings from the decoded JSON.
“statically” Analyze the downloaded bytes without running the sample. Kept the ELF and archive as data; the plug-in only reads and transforms bytes.

Safety

This was static analysis only. No sample was executed. The assigned archives and extracted ELF stayed in the Homebase's local work directory.

What was in the files

Each mode delivered an encrypted evidence.zip with 3,159 archive members and one Day 19 ELF. The Single Solve archive contained d19--variant-000.elf (11,232 bytes). Time Trial used d19--variant-001.elf; Mastery used five variants (000, 007, 006, 005, and 004). All had the same overlay layout, while their ELF bytes and decoded HCFG CRCs differed.

In the Single Solve ELF, the final PK19 overlay began at byte offset 10808 and occupied 424 bytes. Its 44-byte header held two transform keys, the packed payload length, and the SHA-256 expected after decoding. The transform was ror8(byte XOR k2, 3) XOR k1. The decoded bytes began with an HCFG record: version 1, a one-byte XOR key, payload length, stored CRC32, then XOR-encoded JSON. The plug-in verified both checksums before using the JSON fields.

The Homebase agent's new plug-in handles those eight Day 19 configuration and overlay fields. The existing binary solver and other plug-ins covered the other 220 fields. Offline coverage for the full question set was 228/228.

Single Solve

Our automated morning solver started this attempt at 13:00:34 UTC and sent its answers in untimed batches between 13:00:37 and 13:00:39. Those covered the 220 fields that earlier days' solvers already knew. The eight new Day 19 fields were left open, so the rest of the Binary lane went to the Homebase agent. Offline coverage identified the eight Day 19 overlay fields that were missing from the existing solver chain. Those eight answers came from the downloaded, hash-verified archive; no candidate guessing or rejected values were recorded. The Game Master returned CORRECT.

The Homebase agent used its new plug-in to find the final PK19 marker, reverse the byte transform, validate the embedded SHA-256, parse the HCFG record, verify its CRC32, then read the four requested JSON values and four header/overlay properties. The solver implementation is described here but not reproduced.

Field Recovered value
d19_analysis_config_campaign BR19-000
d19_analysis_config_domain node-000.day19.example.invalid
d19_analysis_config_mutex Global\HuntressBR19_000
d19_analysis_config_url https://node-000.day19.example.invalid/api/BR19-000
d19_analysis_config_crc32_hex 0xd02e2211
d19_analysis_hcfg_version 1
d19_analysis_overlay_offset 10808
d19_analysis_overlay_size 424
started_at: 2026-10-19T13:00:34.767Z (morning solver)
deadline: none (Single Solve)
morning solver batches: 13:00:37Z–13:00:39Z (220 known fields)
answers submitted by the Homebase agent: 8
start / artifact / solve timings: not recorded
submit: request at 13:09:47Z; HTTP 200 at 13:09:48Z (~1 second, log precision)
TOTAL from first start: ~9 min 14 s (13:00:34Z to 13:09:48Z)
result: CORRECT — 7c98f5ae…860c (read back later from a status call; the saved reply was truncated)

Time Trial

The plain start was untimed and unranked. The solver covered all 228 answer IDs and the submission returned CORRECT. There were no failed submissions or rejected values.

started_at: 13:10:24Z (successful start response; second-level precision)
deadline: none; unranked (start reply)
answers: 228
start request / response: 13:10:23Z–13:10:24Z (~1 second)
artifact / solve timings: not separately recorded
submit request / response: 13:10:30Z–13:10:31Z (~1 second)
TOTAL from successful start response to CORRECT response: ~7 seconds (log precision)
result: CORRECT — 8f800331…52fe

Mastery

Mastery contained five sets and 1,140 answer fields. The plain start was untimed and unranked. All five assigned archives were processed, and the submission returned CORRECT on the single run.

started_at: 13:10:52Z (successful start response; second-level precision)
deadline: none; unranked (start reply)
answers: 1,140 across 5 sets
start request / response: 13:10:49Z–13:10:52Z (~3 seconds)
artifact / solve timings: not separately recorded
submit request / response: 13:11:06Z–13:11:10Z (~4 seconds)
TOTAL from successful start response to CORRECT response: ~18 seconds (log precision)
result: CORRECT — 3419fbaf…a090

Time to solve

All three modes were solved by 13:11:10 UTC (09:11:10 ET), 10 min 36 s after the first start; most of that was the hand-over to the Homebase agent and its new plug-in. The Single Solve went through at 13:09:48, and the untimed, unranked Time Trial (~7 s) and Mastery (~18 s) each went through on the first submit.

Takeaways

  • Verify each decode layer. A valid-looking configuration is not enough; check the PK19 SHA-256 and HCFG CRC32 before using its fields.
  • Treat overlays as file data. The PK19 record was appended after the ELF's ordinary content, so ELF section parsing alone would miss it.
  • Keep the decoder variant-neutral. Read transform keys, lengths, and expected hashes from the assigned bytes instead of storing variant-specific answers.
  • Use exact answer IDs and formats. The config values are exact text, the CRC is padded hexadecimal, and version/offset/size are base-10 integers.