zwesty
Write-ups / Day 22 / Warmups
Day 22 · Thu, Oct 22 · Warmups

Deflated Ego

Prey slaughtered

zlib under Base64 (eN), rail-fence transposition, keeping every reading of a layer in play, rehearsal limits

STTMClaude Homebase Both

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

Challenge ID
warmups-day-22 (+ /time_trial, /mastery)
Solved
2026-10-22: Single Solve and Time Trial CORRECT on the first submit (09:00:44 and 09:00:52 ET, the Time Trial ranked). The ranked Mastery got 106 of 108 and expired. One untimed retry was CORRECT at 09:05:03 ET, 4 min 21 s after the solver's first start request on this lane (09:00:42 ET). The scheduled run started on time (08:58:01). Without the Mastery gap the lane would have been done by about 09:01:00
Player
Zwesty (solo), with Claude Code (Opus 5.5): our automated morning solver (a scheduled script on our Kali VM) did the Single Solve, the Time Trial, and the ranked Mastery; Claude found the gap, built the fix, ran the checks, and sent the untimed retry

The challenge

"Another familiar wrapper. This one needs a little inflation."

answer_id Question Format
message "Decode the assigned blob completely. What exact answer slug does its final non-empty decoded line instruct you to submit?" pattern: "three lowercase words separated by hyphens, followed by a hyphen and a two-digit number; submit the slug only"; trimmed

Mastery asked the same question once per blob (set1.message … set108.message).

Reading the prompt: what it said we'd need

Clue What it pointed to What I did about it
"Another familiar wrapper" Base64 again, as on Day 21 ("A familiar wrapper") Nothing new: Base64 has been in the chain since Day 1
"a little inflation" Inflate, the decompression side of deflate. The Base64 starts eN, which decodes to 78 da, the zlib header The chain already tries zlib, gzip, bz2, xz, and raw deflate under Base64 (pre-built for Day 15)
"Deflated Ego" (title) Deflate Confirmed the reading
"Decode the assigned blob completely" Every line of a Mastery blob, old layers included This is where it failed: one of the old layers (Day 18's rail fence) had a reading the chain never tried

What was in the files

  • Single Solve: blob.txt, 136 bytes: one line of Base64 starting eNolyTEO…. It inflates to the usual sentence: "Nice work decoding this warmup! To solve, submit this exact answer to the Game Master: tidy-cloud-tulip-70".
  • Time Trial: blob.txt, 136 bytes, the same template with a different slug (proud-squirrel-clover-79).
  • Mastery: one zip of 108 blobs (blob-01.txt … blob-108.txt, 510 to 534 bytes; 67,357 bytes for the ranked attempt, 67,323 for the retry). Each has 22 labelled lines (NN<TAB>…) in the history pattern of the earlier days. Line 21 is Base64 gzip (H4sI…, Day 21's layer) and line 22 Base64 zlib (eN…, today's layer). For example, line 22 of the retry's blob-01.txt inflates to the fragment ne-26.
  • Line 18 is Day 18's rail-fence layer, usually a 4-character fragment. In the ranked attempt, blob-45.txt and blob-68.txt both had stre there.

So the timed variants used the same template with different values, and the Mastery added today's layer as one more line.

Single Solve

The solver solved it with no stop, still using the Day 19 Warmups solver, unchanged since Day 19. The zlib reading wasn't new: it was pre-built for Day 15 (zlib, gzip, bz2, xz, and raw deflate under Base64 and the other wrappers, detected by magic bytes) and carried forward through the Day 16 version.

started_at  2026-10-22T13:00:42.529Z
deadline    none (Single Solve)
answers     1   tidy-cloud-tulip-70
start        390 ms
artifact     277 ms
solve         12 ms
submit      1110 ms
TOTAL       1789 ms   (submit +1.50 s after started_at)
result      CORRECT   flag 87cbfb7b…7d9a

Time Trial

CORRECT on the first attempt, ranked. The start reply showed unique_attempts_remaining: 255.

started_at  2026-10-22T13:00:49.788Z
deadline    2026-10-22T13:01:19.788Z   (30 s)
answers     1   proud-squirrel-clover-79
start        740 ms
artifact     958 ms
solve         10 ms
submit      1237 ms
TOTAL       2944 ms   (submit +2.30 s after started_at)
result      CORRECT   flag 44b841ad…79ee

Mastery

Ranked attempt: 106 of 108, expired

started_at  2026-10-22T13:00:57.752Z
deadline    2026-10-22T13:03:02.752Z   (125 s)
answers     106 of 108 (set45 and set68 not in the submit)
start        687 ms
artifact     641 ms
solve        857 ms
submit       293 ms
TOTAL       2477 ms   (submit +1.91 s after started_at)
result      accepted, remaining 2; no further submit, so the attempt expired at the deadline

What went wrong. In sets 45 and 68, line 18 was stre. Read on 3 rails it is ster (the end of "…Game Ma|ster: …"). The older readings of a short line were Base64 or hex junk, plus the 2-rail reading srte. Day 19's rail search (2 to 12 rails) only runs when the older readings come back empty. They never do for a short line, so 3 rails was never tried. With no instruction line found for those two sets, they had no answer. The solver stopped there; it is set not to retry on its own.

Nothing was burned. The ranked submit had 106 keys and no set45 or set68, so no wrong value was sent. An early version of our notes named two "burned" values. The request log showed they were Day 21's accepted set45/set68 answers, found by a log search that wasn't limited to Day 22, so the notes were corrected.

The fix

Our solver (loading the Day 19 solver by its own path): it always adds the standard (phase-0) rail-fence readings for 2 to min(12, n−1) rails, next to the older readings, for lines of 4 to 512 characters with at least one letter. The sentence search then picks the reading that makes sense.

Checks before the retry: - The failed set replayed: 108 of 108 solved in 0.67 s, with all 106 accepted answers unchanged. Sets 45 and 68 now give tidy-cabin-onyx-18 and spry-tent-trail-40 (never sent, because that attempt had expired, so unconfirmed). Set 44 is unchanged (zippy-blanket-trail-96). - Rehearsal: a regression rehearsal over 94 saved attempts, plus 60 synthetic blobs with today's zlib layer: 93 identical, 1 newly solved, 0 changed; synthetic 60 of 60. It passed. - No separate unit tests were written; the replay and the rehearsal were the tests.

Untimed retry: CORRECT

We then ran one untimed retry, using the Game Master's retry without asking for a ranked run. The reply confirmed it was unranked, so this Mastery has no ranked time.

started_at  2026-10-22T13:05:01.457Z   (retry, untimed)
deadline    none
answers     108
retry       ~1616 ms  (TOTAL minus the logged phases)
artifact     351 ms
solve        702 ms
submit      1399 ms
TOTAL       4069 ms   (submit +2.53 s after started_at)
result      CORRECT   flag dd273f70…0203

Afterwards, at 09:05:10 ET, the fixed solver became the one the scheduled job uses.

Time to solve

The Single Solve (09:00:44 ET) and the ranked Time Trial (09:00:52 ET) each went through on the first submit. The ranked Mastery answered 106 of 108 and expired; after about four minutes of diagnosis, fix, replay, and rehearsal, one untimed retry went through at 09:05:03 ET, 4 min 21 s after the lane's first start and 5 min 3 s after release, so the Mastery is unranked.

Takeaways

  • Don't gate a reading on "the older ones found nothing". Junk readings of a short line are never empty, so the Day 19 rail search was starved. Give each reading its own slot and let the sentence search choose.
  • The synthetic rehearsal couldn't see this. Its rail-fence generator uses 2 rails for strings of 4 characters or fewer. A test at the real fragment lengths, with 3 rails, would have caught it before the day.
  • Today's layer was the easy part. The zlib reading was pre-built a week early and worked first time; the miss was a four-day-old layer in a new combination.
  • Filter log searches by day and attempt. An unfiltered search briefly put Day 21's answers into Day 22's record.
  • One missed set costs the whole ranked Mastery. 106 of 108 is still not CORRECT, and the retry has no ranked time.