zwesty
Write-ups / Day 29 / Script
Day 29 · Thu, Oct 29 · Script

Make It Make Sense

Prey slaughtered

Static script triage across languages; reading each fixture's embedded analysis plan; role, ATT&CK mapping, stage graph, and indicators for a new host language (Makefile)

STTMClaude Homebase Both

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

Challenge ID
script-analysis-day-29-makefile-variant-diff (+ /time_trial, /mastery)
Solved
2026-10-29: all three modes CORRECT, both timed modes ranked, each timed mode on its first submit. Single 09:05:26.8 ET (two submits: core, then plug-ins), Time Trial 09:05:34.5, Mastery 09:05:44.9: 21.4 s from the Single's start (09:05:23.5) to the Mastery CORRECT, 5 min 44.9 s after release
Player
Zwesty (solo), with Claude Code (Opus 5.5): our automated morning solver (a scheduled script on our Kali VM) solved all three modes on its own with our existing Script solver and its plug-ins. No one worked this challenge by hand, and no code was changed

The challenge

"Unseen Makefile variants and their prior-language build chains differ in layered variables and target flow. Diff them carefully, and keep only the tradecraft conclusions that hold up across every variant."

Script is cumulative: 1,747 questions on one evidence.zip. 44 were new, all polyglot-makefile-*: four Makefile fixtures with 11 fields each. Every other id had been asked on an earlier Script day.

answer_id (pattern) Question Format
polyglot-makefile-<fixture>-role (fixtures benign-utility, downloader, launcher, staged-chain) "Classify the inert source role." enum (benign_utility, downloader, dropper, impact, …)
…-attack "Map the decoded ordered behavior graph to one primary MITRE ATT&CK technique using this precedence: …" (the question spells out the precedence) pattern: ATT&CK technique or sub-technique ID
…-steps "Recover the ordered behavior graph using > separators." ordered_tokens: "exact tokens joined by > with no surrounding spaces"
…-adapter, -campaign, -file-path or -url, -host-profile, -obfuscation, -stage-profile, -next-language "Recover the exact …" exact text
…-stage-count "Recover the modeled stage count." integer

The other 1,703 questions covered the earlier languages: polyglot fixtures in other languages (1,012 polyglot ids in all), Bash 168, script hosts 154, Python 126, JScript, Batch and VBScript 72 each, Node.js 56, and 15 resource / collection / impact fields. The Time Trial asked 1,833 (52 on Makefiles); the Mastery asked 13 sets, 23,829 (676 on Makefiles).

Reading the prompt: what it said we'd need

Clue What it pointed to What the solver did about it
"Unseen Makefile variants" A new host language: Makefiles Four .mk fixtures, 44 new question ids. The core answered all 44 in its first batch
"their prior-language build chains" The earlier days' languages in the same evidence The same cumulative questions as before, answered by the same rules
"layered variables and target flow" How the stages are encoded and the order they run in The obfuscation, steps, and stage-profile fields
"keep only the tradecraft conclusions that hold up across every variant" The answers must survive fresh variants The Time Trial and 13 Mastery sets, each with new values, all CORRECT first time
"Make It Make Sense" (title) make, the build tool Confirmed the reading

Safety

Static analysis only. Nothing was executed. The fixtures are inert by design ("Classify the inert source role"), and the solver reads them as text. For this write-up only the saved replies, the solver's output, archive listings (names and sizes), and the solver source were read; the .mk members were not opened. Indicators below are defanged.

What was in the files

  • Single Solve: evidence.zip, 159,137 bytes, 183 members. The new ones: polyglot-makefile-benign-utility.mk (1,172 bytes), polyglot-makefile-downloader.mk (2,333), polyglot-makefile-launcher.mk (1,857), and polyglot-makefile-staged-chain.mk (1,736).
  • Time Trial: evidence.zip, 179,816 bytes, the same template with fresh values. The solver's output shows the kind of values: a Terraform fixture's file path under /tmp/huntress-terraform_hcl/, a host terraform_hcl-…[.]example[.]invalid, and an 8-hex campaign token.
  • Mastery: script-analysis-day-29-makefile-variant-diff-mastery.zip, 2,348,727 bytes, 13 sets.

Single Solve: the automated solver

The solver sent its answers in two batches: the core Script solver's, then the plug-ins'.

started_at  09:05:23.5 ET   deadline none
submit 1    core: 1,620 answers            -> accepted (127 remaining)
submit 2    plug-ins merged: 127 answers   -> CORRECT
start        485 ms
artifact     325 ms   (159,137 bytes)
solve        949 ms
submit      2613 ms   (core 671 ms, plug-ins 1,939 ms)
TOTAL       4377 ms
result      CORRECT   flag 9579faf3…14bb   (09:05:26.8 ET)

Why no change was needed: all 44 Makefile answers were in the core's first batch of 1,620 and were accepted. Since Day 8 the core has answered polyglot fixtures from the analysis plan each one carries (a HUNTRESS_ANALYSIS_V1:<encoding>-<payload> header that decodes to a v=3|key=value|… plan). Our solver has no Makefile-specific code, so the Makefiles went through the same path as the other polyglot languages. The 127 plug-in answers were older JScript (72), script-host (33), Batch (15), and VBScript (7) fields, which the plug-ins already owned.

One warning, and it was harmless. Before the core batch the solver noted that some values had been "rejected on another question before (still sent)", among them polyglot-makefile-benign-utility-attack=none and polyglot-makefile-downloader-attack=T1105. They went in anyway, and the batch was accepted.

Time Trial

CORRECT on the first attempt, ranked (fresh variant).

started_at  09:05:33.5 ET   deadline 09:06:23.5 (50 s clock)
answers     1,833
start        745 ms
artifact     301 ms   (179,816 bytes)
solve         79 ms
submit      1219 ms
TOTAL       2346 ms   (submit +1,836 ms after started_at)
result      CORRECT   flag 3080e8f5…3565   (09:05:34.5 ET)

Mastery

CORRECT on the first attempt, ranked (fresh variant).

started_at  09:05:41.4 ET   deadline 09:12:31.4 (6 min 50 s clock)
answers     23,829 (13 sets)
start       1604 ms
artifact     692 ms   (2,348,727 bytes)
solve       1490 ms
submit      1885 ms
TOTAL       5719 ms   (submit +4,901 ms after started_at)
result      CORRECT   flag 4f090b3a…a814   (09:05:44.9 ET)

Speed boards (final boards; time = server start to solve): - Time Trial: 6th of 42, 1.020 s (fastest 0.630 s). - Mastery: 3rd of 39, 3.504 s (fastest 1.122 s).

Time to solve

The Single was CORRECT at 09:05:26.8 ET, 3.3 s after its start; the ranked Time Trial (09:05:34.5) and ranked Mastery (09:05:44.9) each went through on the first submit, 21.4 s after the Single's start and 5 min 44.9 s after release. Script was the last of the solver's lanes that morning.

Takeaways

  • A generic reader handles a new language for free. The core reads the plan each fixture carries, not the language around it, so Makefiles needed nothing new.
  • Read the fresh-variant clue as a test, not a task. "Holds up across every variant" meant the Time Trial and 13 Mastery sets; the same rules passed all of them first time.
  • A "rejected before" note is a warning, not a stop. The solver sent those values anyway, and they were right for these questions.
  • Last in the solver's order and still finished by 09:05:45, with the Mastery 3rd of 39 on the speed board.