zwesty
Write-ups / Day 25 / Binary
Day 25 · Sun, Oct 25 · Binary

Out of Bounds

Prey slaughtered

Static JAR triage (ZIP container, class files), Base64 constants, HCFG config record with CRC32, cumulative question sets, add-on modules written for day >= N

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-25-synthetic-vulnerability-root-cause (+ /time_trial, /mastery)
Solved
2026-10-25: all three modes CORRECT on the first submit, by 09:01:37 ET, 27 s after the first start request on this lane (09:01:10 ET) and 1 min 37 s after the 9 AM release. Both timed modes were ranked runs
Player
Zwesty (solo), with Claude Code (Opus 5.5): our automated morning solver (a scheduled script on our Kali VM) did all three modes, with no hands-on work needed

The challenge

"Somewhere in here, the code reaches where it shouldn't. Prove the bounds error is real, trace its reachability, and compare against the corrected twin that learned its limits."

Binary is cumulative: 300 questions, 12 per day for Days 1–25, all on one evidence.zip. The 12 Day 25 fields are the same 12 as Day 24's, renamed d25_:

answer_id Question (short) Format
d25_artifact_sha256_1, _2 SHA-256 of d25-- members 1 and 2, in ZIP central-directory order 64 lowercase hex
d25_analysis_vulnerable_format, d25_analysis_corrected_format Classify the member ending vulnerable.jar / corrected.jar by magic and container enum: elf, pe, pe_cli, jar, wasm, neko_bytecode
d25_analysis_config_campaign, _domain, _mutex, _url "Decode both d25-- role members and require their config objects to be byte-for-byte equal before using the common value", then the HCFG JSON fields exact text
d25_analysis_corrected_config_campaign, _domain, _mutex, _url The same HCFG fields, from the corrected.jar member only exact text

The HCFG rule in the question text: parse every class file's constant pool; Base64-decode every Base64-alphabet UTF-8 constant of at least 80 characters; take the first CRC32-valid HCFG JSON record (HCFG, version byte, XOR key byte, little-endian payload length, CRC32 of the decoded payload, payload from byte 12). The Time Trial asked the same 300; the Mastery asked them once per set (9 sets, 2,700 answers).

Reading the prompt: what it said we'd need

Clue What it pointed to What I did about it
"the code reaches where it shouldn't … bounds error" An out-of-bounds read or write in one method None of the 12 Day 25 questions asked for it. The answers come from the containers and the embedded config
"trace its reachability" A call path to the bug Not asked either
"the corrected twin that learned its limits" Two builds: d25--sample-vulnerable.jar and d25--sample-corrected.jar Both JARs: format jar for each, and the corrected build's config read on its own
"require their config objects to be byte-for-byte equal" (question text) Both builds carry the same HCFG config The solver's core decodes both and checks they match
"Use the unique d25-- member whose basename ends corrected.jar" (question text) The config from the corrected build alone Day 24's add-on reads exactly that, for every day from 24 on

Safety

Static analysis only. Nothing was executed. The JARs were opened as ZIP files and their class files read as bytes (Base64 runs, then the HCFG scan); no Java runtime was started. For this write-up only the archive's member list and the solver's record of accepted answers were read. The archives stayed on our Kali VM. Indicators below are defanged.

What was in the files

  • Single Solve: evidence.zip, 35,699,576 bytes, password-protected members covering Days 1–25. Today's members are d25--sample-vulnerable.jar (8,282 bytes, member 1) and d25--sample-corrected.jar (8,417 bytes, member 2), about twice the size of Day 24's pair. SHA-256: cc14d96c…2553 and 8fab8d49…5eac.
  • The HCFG record, the same in both builds (defanged): campaign BR25-000, domain node-000[.]day25[.]example[.]invalid, mutex Global\HuntressBR25_000, URL hxxps://node-000[.]day25[.]example[.]invalid/api/BR25-000. The same 000 template as Day 24's.
  • Time Trial: one evidence.zip of 35,834,462 bytes. Its corrected build's config was randomised: campaign BR25-48205BAA, domain mesh-c19bf0f7[.]day25[.]example[.]invalid, mutex Global\HuntressE7749F3A4106, URL hxxps://node-bf546f0b[.]day25[.]example[.]invalid/gate/f0ed2c99a3. Note that the URL's host is not the domain field, so the fields can't be derived from each other.
  • Mastery: nine archives, 35.67 to 35.83 MB each, streamed. Same template with different values.

Single Solve

The solver got it in two batches, with no stop.

  • Core: 211 answers, accepted, 89 remaining. Its Day 25 answers were the two SHA-256s and the four common-config fields (it decodes both builds and requires the configs to match).
  • Add-ons merged: 89 answers, among them the two *_format fields and the four corrected_config_* fields, from the add-on module Claude wrote on Day 24. It accepts any Binary day ≥ 24, so today it needed no change: jar when the member is a ZIP whose entries include .class files, and the corrected JAR's own HCFG config through the shared HCFG reader.
started_at  2026-10-25T13:01:10.386Z
deadline    none (Single Solve)
answers     211 core (accepted, remaining 89), then 89 add-on answers
start        543 ms
artifact    1713 ms   (35.7 MB)
solve       1046 ms
submit      1899 ms   (core 243, add-ons 1654)
TOTAL       5202 ms
result      CORRECT   flag bd8f7977…6805

Unlike Day 24, the Single Solve flag is on file: the solver saved the submit reply (our request log cuts replies at about 4,000 characters, so its copy has no flag).

Time Trial

CORRECT on the first attempt, ranked (80 s clock).

started_at  2026-10-25T13:01:21.520Z
deadline    2026-10-25T13:02:41.520Z   (80 s)
answers     300
start        592 ms
artifact    1626 ms   (35.8 MB)
solve        726 ms
submit       741 ms
TOTAL       3685 ms   (submit +3.23 s after started_at)
result      CORRECT   flag 468c3041…8863

Mastery

CORRECT on the first attempt, ranked (9 sets, 595 s clock; Day 24 had 8 sets and 530 s). The nine archives were streamed.

started_at  2026-10-25T13:01:31.321Z
deadline    2026-10-25T13:11:26.321Z   (595 s)
answers     2,700 (9 sets × 300)
start        377 ms after started_at
artifact    5068 ms after started_at   (9 × ~35.7 MB, streamed; first in, set 8, at +2411 ms)
solve       5735 ms after started_at   (667 ms after the last archive)
submit      7090 ms after started_at
TOTAL       7813 ms
result      CORRECT   flag 559301f9…531f

No code was changed for this lane today.

Time to solve

All three modes were solved by 09:01:37 ET, 1 min 37 s after release (27 s from the first start request on this lane). The Time Trial and Mastery were both ranked and each went through on the first submit.

Takeaways

  • Writing add-ons for day >= N paid off the next day. Day 24 needed Claude and 2 min 29 s; today the same six fields came from that add-on and the lane took 27 s on the solver alone.
  • The prompt's theme didn't change the questions, a third day running. "Bounds error" and "reachability" sounded like bytecode analysis; the 12 fields were hashes, formats, and the config. Read the question list before planning around the prompt.
  • Timed configs are randomised, and their fields don't agree with each other. The TT's URL host wasn't its domain field. Read each field from the record; never build one from another.
  • Keep every reply that carries a flag. The solver's saved per-batch submit replies kept today's Single Solve flag, which the request log alone would have lost.