zwesty
Write-ups / Day 20 / Binary
Day 20 · Tue, Oct 20 · Binary

Resourceful

Prey slaughtered

Static ELF triage, overlay (bytes past the last section) location, a custom resource-overlay header (RS20) with bounds and SHA-256 checks, HCFG config records with CRC32, cumulative question sets

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-20-resources-and-overlays (+ /time_trial, /mastery)
Solved
2026-10-20: all three modes CORRECT in the morning, Time Trial and Mastery unranked. Single Solve 09:16:49.3 ET, Time Trial 09:22:12.7, Mastery 09:22:35.7. 21 min 18.2 s from the first start (09:01:17.4 ET) to the Mastery CORRECT. First ranked Time Trial and Mastery on 2026-10-22 from 23:16 ET (five ranked runs, all CORRECT)
Player
Zwesty (solo), with the Homebase agent (GPT-6 Luna) and Claude Code (Opus 5.5). Binary was the Homebase's lane on Days 20–22. Our automated morning solver (a scheduled script on our Kali VM) started the Single Solve and sent the 238 answers it could cover; the Homebase agent wrote the missing plug-in, sent the last 2 answers, and ran unranked Time Trial and Mastery runs; Claude ran the ranked runs two days later

The challenge

"Binaries have attics: resources, overlays, bytes past the end of the sections. Rummage through this one's hidden storage and map every boundary."

Binary is cumulative: 240 questions, 12 per day for Days 1–20, all on one evidence.zip. The 12 Day 20 fields:

answer_id Question (short) Format
d20_artifact_sha256_1 SHA-256 of the one d20-- member 64 lowercase hex
d20_analysis_format Classify the member by magic and container enum: elf, pe, pe_cli, jar, wasm, neko_bytecode
d20_analysis_architecture Architecture from the executable header name, tool label, or machine code
d20_analysis_machine Architecture from the header's machine field "label or its equivalent decimal or hexadecimal code"
d20_analysis_config_campaign, _domain, _mutex, _url Fields of the HCFG record inside the final RS20 overlay's resource exact text
d20_analysis_config_crc32_hex HCFG header bytes 8..11 0x + 8 lowercase hex
d20_analysis_hcfg_version HCFG header byte 4 base-10 integer
d20_analysis_hcfg_resource_size The RS20 header's HCFG resource size field base-10 integer
d20_analysis_overlay_offset Zero-based offset of the final RS20 magic in the member base-10 integer

The config questions spelled out the RS20 layout: resource length u32le at +8, scratch length u16le at +12, scratch SHA-256 at +16..+47, the HCFG resource from +48, scratch after it; check the end bounds and the scratch hash, then decode the HCFG record (XOR key at byte 5, CRC32 at bytes 8..11).

The Time Trial asked the same 240; the Mastery asked them once per set (5 sets, 1,200 answers).

Reading the prompt: what it said we'd need

Clue What it pointed to What was done about it
"resources, overlays, bytes past the end of the sections" Data appended after the last ELF section, not in any section The answers sit in an RS20 overlay near the end of the ELF member, found by its magic
"Rummage through this one's hidden storage" A container inside the overlay The overlay holds an HCFG resource plus scratch bytes; the question text gave the exact header layout
"map every boundary" Offsets and sizes, checked Two new numeric fields (overlay offset, resource size), and the question demanded the end-bounds and scratch SHA-256 checks before trusting the record
"final RS20 overlay" (question text) There could be more than one magic match Take the last RS20 in the member

Safety

Static analysis only. Nothing was executed. The Homebase agent's notes record that no sample was run and that its plug-in only parses the assigned archive bytes. Claude's ranked runs used the same static solver. The archives stayed on our Kali VM and on the Homebase.

What was in the files

  • Single Solve: evidence.zip, 33,207,971 bytes, 23 encrypted members covering Days 1–20. Today's member is d20--variant-000.elf (1,201,351 bytes).
  • The overlay: the final RS20 magic is at offset 1,200,888, so the overlay is in the last 463 bytes of the file. Its HCFG resource is 380 bytes.
  • The HCFG record decoded to a synthetic config (defanged): campaign BR20-000, domain node-000[.]day20[.]example[.]invalid, mutex Global\HuntressBR20_000, URL hxxps://node-000[.]day20[.]example[.]invalid/api/BR20-000, CRC32 0x570dddce, version 1.
  • Header fields: format elf, architecture x86-64, machine 62 (the decimal e_machine value was accepted here).
  • Time Trial: one evidence.zip of 33.2–33.3 MB per attempt. Mastery: five archives of 33.2–33.3 MB each. Same 240 questions with different values; the Homebase's unranked runs and all of Claude's ranked runs were answered by the same rules.

Single Solve

The morning solver: 238 sent, 2 open

The solver started the Single Solve at 09:01:17 and sent two batches, both accepted. It then reported 238 of 240 covered and left the rest, and the timed modes, to the Homebase. The two open fields were the new d20_analysis_hcfg_resource_size and d20_analysis_overlay_offset. The records don't say why the first batch went in five minutes after the start.

started_at  2026-10-20T13:01:17.433Z   (solver)
deadline    none (Single Solve)
submit 1    197 core answers      -> accepted, remaining 43   (13:06:21Z)
submit 2    41 add-on answers     -> accepted, remaining 2    (13:06:22Z)
result      not CORRECT: 2 fields uncovered, nothing rejected; timed modes not started

The plug-in and the finish (Homebase agent)

The Homebase agent wrote a new plug-in for days ≥ 20, a static RS20 reader: - d20_analysis_overlay_offset: the zero-based offset of the final RS20 magic in the Day 20 ELF member. - d20_analysis_hcfg_resource_size: the u32le at overlay +8, after checking the resource and scratch bounds and the scratch SHA-256.

Its coverage check came to 240 of 240. It reopened the solver's attempt and sent the two values. No value was rejected.

started_at  2026-10-20T13:01:17.433Z   (same attempt, reopened by the Homebase at 13:16:42Z)
answers     d20_analysis_hcfg_resource_size 380, d20_analysis_overlay_offset 1200888
result      CORRECT   flag 75759d6a…22ce   (server stamp 13:16:49.343Z)

Time Trial

Homebase, unranked (2026-10-20)

CORRECT on the first attempt, not ranked (no deadline).

started_at  2026-10-20T13:22:06.030Z
deadline    none (unranked)
answers     240
start        162 ms after started_at
artifact    4644 ms
solve       6329 ms
submit      7116 ms after started_at
result      CORRECT   flag 538f31bc…4090   (server stamp 13:22:12.654Z)

Claude, ranked (2026-10-22 evening)

Three ranked runs (80 s clock), all CORRECT on the first submit.

run         1                   2                   3
started_at  03:16:37.749Z       03:36:54.640Z       03:40:33.271Z      (2026-10-23 UTC)
answers     240                 240                 240
retry       +180 ms             +166 ms             +162 ms
artifact    +3874 ms            +2064 ms            +2333 ms           (33.2–33.3 MB)
solve       +4570 ms            +2762 ms            +3085 ms
submit      +5984 ms            +3654 ms            +3839 ms           after started_at
result      CORRECT             CORRECT             CORRECT            flag 538f31bc…4090

Board: 17th at 4.802 s after the first run; 8th at 2.985 s after the other two. Final board on 2026-11-01: 9th of 73, 2.985 s.

Mastery

Homebase, unranked (2026-10-20)

CORRECT on the first attempt, not ranked. Five archives, 1,200 answers.

started_at  2026-10-20T13:22:19.174Z
deadline    none (unranked)
answers     1,200 (5 sets × 240)
start        216 ms after started_at
artifact    7896 ms   (5 × ~33.3 MB)
solve      16110 ms
submit     17073 ms after started_at
result      CORRECT   flag aec72ba2…9873   (server stamp 13:22:35.662Z)

Claude, ranked (2026-10-22 evening)

Two ranked runs (325 s clock), with the archives streamed by 3 workers, both CORRECT on the first submit.

run         1                   2
started_at  03:16:54.496Z       03:37:24.229Z      (2026-10-23 UTC)
answers     1,200               1,200
retry       +305 ms             +282 ms
artifact    +4840 ms            +4395 ms           (5 archives streamed, last one in)
solve       +5895 ms            +5013 ms
submit      +6983 ms            +6410 ms           after started_at
result      CORRECT             CORRECT            flag aec72ba2…9873

Board: 7th at 6.256 s after the first run; 6th at 5.383 s after the second. Final board on 2026-11-01: 7th of 67, 5.383 s.

Time to solve

All three modes were solved by 09:22:35.7 ET, 22 min 35.7 s after release (21 min 18.2 s from the first start request); the Single Solve waited about 10 minutes for the new plug-in, and no value was rejected in any mode. The morning Time Trial and Mastery were unranked; the ranked times came from Claude's runs on the evening of 2026-10-22 (Time Trial 2.985 s, Mastery 5.383 s on the board).

Takeaways

  • A solver that stops on uncovered fields costs nothing. It sent the 238 answers it was sure of and left 2 open; the attempt stayed open for the Homebase to finish, with no rejected value.
  • The question text was the parser spec. The RS20 layout (offsets, lengths, the scratch hash) was written out in the question, so the new plug-in needed no guessing.
  • "Final" means the last match. The offset and the resource size both come from the last RS20 magic in the member.
  • Write plug-ins for day >= N. The RS20 reader applied to days ≥ 20, and the same two Day 20 fields were answered again on Day 21 by the same plug-in.
  • Unranked runs leave the board empty. The morning Time Trial and Mastery weren't ranked, so the routes had no board time until Claude's ranked runs two days later.