The challenge
"Two binaries, same source, different compiler moods. Diff the variants, account for every optimization, and prove they're semantically the same program."
Binary is cumulative: 406 questions, 14 per day for Days 1–29, all on one evidence.zip. The 14 for Day 29:
| answer_id | Question (shape) | Format |
|---|---|---|
d29_, _ |
SHA-256 of member 1 / 2 of the d29- members in ZIP central-directory order |
64 lowercase hex |
d29_ |
"Use the unique d29-- member whose basename ends O3.elf" (or O0.); classify by magic and parsed container |
enum (elf, pe, pe_, jar, wasm, neko_) |
d29_ |
The same member: "Read the ELF e_machine field and submit its unsigned base-10 numeric value" | integer |
d29_ |
"Decode both d29-- role members and require their config objects to be byte-for-byte equal before using the common value"; scan backward for HCFG, first CRC32-valid record | exact text |
d29_ |
The O3. build alone: scan backward from the end for HCFG, first CRC32-valid decoded JSON record |
exact text |
The Time Trial asked the same 406; the Mastery asked them once per set (13 sets, 5,278 answers).
Reading the prompt: what it said we'd need
| Clue | What it pointed to | What the solver did about it |
|---|---|---|
| "Two binaries, same source" | A pair of builds of one program | d29- and d29- |
| "different compiler moods" | Optimization levels: - and - |
The roles unoptimized (O0.) and optimized (O3.), picked by basename, as on Day 27's gcc/tcc pair |
| "Diff the variants, account for every optimization" | Comparing the builds | No question asked for a code diff. The fields were format, machine, and config per build |
| "prove they're semantically the same program" | Show the two builds carry the same thing | The common-config fields require both builds' decoded configs to be byte-for-byte equal before the value is used |
| "Fraternal Twins" (title) | Same parents, not identical | Two builds, same config, different code |
Safety
Static analysis only. Nothing was executed. The solver reads ELF headers and HCFG records as bytes. For this write-up only the saved replies, the solver's output, the archive listing (names and sizes), and the solver source were read. The archives stayed on our Kali VM. Indicators below are defanged.
What was in the files
- Single Solve:
evidence.zip, 35,956,121 bytes, 42 members. Day 29's:d29--sample-O0.elfandd29--sample-O3.elf, 43,931 bytes each. - Time Trial:
evidence.zip, 17,042,042 bytes, the same 406 fields. The solver's output shows theO3.elfbuild's config for this variant: campaignBR29-498F5621, domaingate-f782745a[.]day29[.]example[.]invalid, aGlobal\Huntress…mutex, and async-…URL under the same domain. - Mastery: 13 archives, each an
evidence.zipof about 16.9–17.0 MB, delivered as separate downloads.
Single Solve: the automated solver
The solver sent its answers in two batches: the core Binary solver's, then the plug-ins'.
started_at 09:04:41.7 ET deadline none
submit 1 core: 250 answers -> accepted (156 remaining)
submit 2 plug-ins merged: 156 answers -> CORRECT
start 422 ms
artifact 3494 ms (35,956,121 bytes)
solve 2050 ms
submit 2331 ms (core 362 ms, plug-ins 1,966 ms)
TOTAL 8298 ms
result CORRECT flag 8d1aacb0…2650 (09:04:49.1 ET)
Why no change was needed. Every Day 29 field had an owner before the day began:
- The core answered six: the two member SHA-256s and the four common-config fields. The core already decoded one shared config from both builds of a pair, as it had for the Day 24 pair.
- Our Day 27 plug-in answered the other eight. It was written for Day 27's gcc/tcc builds, but it takes any single-word role and finds the member by the basename ending the question names. So optimized → O3.elf and unoptimized → O0.elf needed nothing new. Its config rule, "scan backward from the end for HCFG, first CRC32-valid record", is the procedure the Day 29 questions spell out. The Day 28 plug-in leaves single-word roles to it, so the two didn't compete.
Time Trial
CORRECT on the first attempt, ranked (fresh variant).
started_at 09:04:57.1 ET deadline 09:06:17.1 (80 s clock)
answers 406
start 1420 ms
artifact 1949 ms (17,042,042 bytes)
solve 747 ms
submit 1840 ms
TOTAL 5957 ms (submit +4,927 ms after started_at)
result CORRECT flag a39b91f8…24c7 (09:05:00.9 ET)
Mastery
CORRECT on the first attempt, ranked (fresh variant). The 13 archives were downloaded in parallel; the last arrived 3,617 ms after started_at.
started_at 09:05:09.5 ET deadline 09:15:29.5 (10 min 20 s clock)
answers 5,278 (13 sets × 406)
downloads 13, done +3,617 ms after started_at
solve 3615 ms
submit 1348 ms
TOTAL 9828 ms (submit +8,589 ms after started_at)
result CORRECT flag 8ed5e6ce…6531 (09:05:17.1 ET)
Speed boards (final boards; time = server start to solve): - Time Trial: 10th of 50, 3.790 s (fastest 1.463 s). - Mastery: 2nd of 47, 7.526 s (fastest 6.410 s).
Time to solve
The Single was CORRECT at 09:04:49.1 ET, 7.4 s after its start; the ranked Time Trial (09:05:00.9) and ranked Mastery (09:05:17.1) each went through on the first submit, 35.4 s after the Single's start and 5 min 17.1 s after release.
Takeaways
- Write plug-ins for the shape, not the day. Our Day 27 role-builds plug-in keyed on "a single-word role, found by basename", so Day 29's
optimized/unoptimizedpair was covered two days before it appeared. - "Prove they're the same" was a config check. The question text defined it: decode both builds' HCFG records and require byte-for-byte equality before answering.
- The prompt's diffing story wasn't asked. No field asked about optimizations or code differences; format, machine, and config were enough.
- Clear ownership kept it fast. Core and plug-ins each took their own fields, and the Mastery placed 2nd of 47.