zwesty
Write-ups / Day 10 / Script
Day 10 · Sat, Oct 10 · Script

Bind Over Matter

Prey slaughtered

Static triage of the Script lane's languages (PowerShell, JScript, Batch, VBScript, Python, Bash, Node, PHP, Lua, and new WMI MOF polyglots), reusing a solver chain unchanged, running it unattended, and handling a rate limit

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-10-wmi-persistence-reconstruction (+ /time_trial, /mastery)
Solved
2026-10-10: Single Solve, Time Trial, and Mastery all CORRECT. 1 h 11 min from the first start (13:00:09 UTC) to the Mastery CORRECT (14:11:06 UTC). Almost all of that was the pause after an HTTP 429; the submits themselves took under half a minute
Player
Zwesty (solo), with Claude Code (Opus 5.5); our automated morning solver (a scheduled script on our Kali VM) did the first pass, and the JScript answers came from an add-on written by the Homebase agent (GPT-6 Luna)

The challenge

"A MOF file declares classes, namespaces, filters, and consumers, but only some bindings actually tie them together. Reconstruct the persistence intent, separate the operational relationships from the decoys, and name the subscription that would really survive a reboot."

753 questions about one AES-encrypted evidence.zip. It was Day 9's 695 unchanged (same ids, same wording, same formats) plus 58 new ones: four WMI MOF polyglots and two more advanced Bash fixtures.

Group Files Questions Format
PowerShell (Day 1's samples) resource- / collection- / impact-sample.ps1 15 enum, T####[.###], exact text
JScript 9 .js (host-context … relay-handoff) 72 (8 each) enum, exact text
Batch 9 .bat / .cmd 72 (8 each, incl. expansion, control, graph) exact text
VBScript 9 .vbs 72 (8 each, incl. representation, transform, control) exact text
Python 14 recovered .py 126 (9 each) enum, exact text
Bash 14 .sh (6 standard, 8 advanced; new: heredoc-reconstruction, here-string) 98 (7 each) enum, integer, ordered tokens
Node 8 .mjs 56 (7 each) enum, integer, ordered tokens
Polyglots 8 PHP, 4 Lua, 4 WMI MOF (polyglot-wmi_mof-benign-utility, -downloader, -launcher, -staged-chain) 176 (11 each) see below
Host fixtures WSF JScript, WSF mixed VBScript, HTA JScript, PHP webshell, .sct scriptlet, OpenResty Lua 66 (11 each) see below

By kind: 489 exact text, 88 enum, 88 ATT&CK IDs, 44 integers, 44 ordered-token lists.

What's new compared with Day 9:

  • The four .mof polyglots get the same 11 questions as every other polyglot: role, ATT&CK ID, adapter, campaign, one indicator (file-path for the benign utility, url for the other three), stage count, steps ("ordered behavior graph using > separators"), host profile, obfuscation ("ordered encoding profile"), stage profile, and next language.
  • The two new Bash fixtures get the advanced-Bash seven: role (advanced_syntax is in the list), the Bash interpreter's ATT&CK ID, feature, primitive, campaign, stage count, and steps.
  • No question asks about bindings, filters, consumers, or "the subscription". No question id or text mentions them. As with Day 9's "impossible family tree", the prompt's last ask isn't a separate question in this delivery.

Reading the prompt: what it said we'd need

Clue What it pointed to What I did about it
"A MOF file declares classes, namespaces, filters, and consumers" WMI event subscription persistence: a MOF file compiled into WMI defines an event filter (the trigger) and a consumer (the action) Looked for MOF in the question list: the four polyglot-wmi_mof-* files. Ran them through the existing polyglot plan reader
"only some bindings actually tie them together" A filter and a consumer do nothing until a __FilterToConsumerBinding joins them; unbound ones are inert No question asks for the binding. The answers come from each file's decoded plan
"separate the operational relationships from the decoys" Surface text in the file that isn't the real plan The plan reader decodes the real bytes and refuses a file whose header and body disagree; none did
"name the subscription that would really survive a reboot" The filter-consumer pair that is actually bound Not a separate question in this delivery (see above)
Question list: two new bash-advanced-* ids Two more advanced-syntax Bash fixtures Day 6's Bash decoder already handled them

Safety

Static only. No script was run, and no MOF file was compiled (mofcomp was never involved). The solver chain reads the files straight out of the AES zip into memory on our Kali VM and parses them as text; JScript is decoded as data by the add-on, never handed to a script host. The artifacts stayed on our Kali VM.

What was in the files

Nobody opened this zip by hand. The solver answered it with the existing chain, so no artifact excerpts were kept, and none are quoted here.

  • What the result shows: Day 9's chain answered all 753 with no new rule and no wrong submit. So the 695 carried-over questions used the same templates with new values, and the four .mof polyglots carry the same kind of plan as the PHP and Lua polyglots (the plan reader answered all 44 MOF questions unchanged). That's an inference from the accepted answers, not something read off the files.
  • The two new Bash fixtures fit the existing advanced-Bash decoder.
  • Time Trial and Mastery used the same templates with new values. The solver answered every timed set unchanged.

Single Solve

  1. The first automated morning. From the night of 2026-10-09 the solver ran on its own, with fixed limits: submit answers from the confirmed solvers only, start the timed modes only after a CORRECT Single Solve, no guesses, no retries, and stop on HTTP 429. It is a plain scheduled script with no AI in it. It woke at 08:58 ET, found the Day 10 list at 9:00 and started this challenge at 13:00:09 UTC.
  2. The core solver (Day 8's, the latest Script chain) sent 626 answers in one batch: accepted, 127 left.
  3. The add-ons sent the rest one by one or in small batches. Four batches (60, 27, 9, and 9) and 16 single answers were accepted. Counting the core batch, that was 22 submits in about 11 s, 17 of them carrying a single answer. At 13:00:21 the Game Master answered the 17th single submit with HTTP 429 rate_limited. 6 left.
  4. The solver stopped there, as designed. It retried nothing, and the timed modes weren't started.
  5. The fix. Claude changed our Game Master client so a submit waits 1 s after the previous one. A timed run's single submit never waits. The client's tests passed 30/30.
  6. Finishing by hand with Claude. A start request at 14:10:38 reconnected to the same attempt (same started_at). Then the 6 open answers went one at a time, about 1.5 s apart: the one refused with the 429 and the five never sent. All six were VBScript control labels from the existing add-on. Five were accepted (remaining 5 → 1) and the sixth returned CORRECT at 14:10:48 UTC (flag 7d503c77…f012).

No wrong submits. Every answer came from the solver chain and add-ons as they stood after Day 9, including the Batch expansion rules and the control labels found on 2026-10-09 (if_guard, error_guard, direct, and the rest; see the Day 9 write-up). JScript answers came from the Homebase agent's JScript add-on, which decodes the plans statically.

Solvers: Day 8's solver and its plan reader, wrapping the chain back through Day 7's Node solver and Day 6's Bash fixes, plus the JScript (Homebase agent), Batch-wording, and VBScript-control add-ons, all called by the morning solver. No separate solver was written for this day.

Time Trial

Run from our Kali VM straight after the Single Solve. Timings are client side; the request log doesn't show a deadline.

started_at  2026-10-10T14:10:57.567Z   deadline (not in the request log)
coverage    753/753, one submit of 753 answers
timings     start 688 ms, artifact 474 ms, solve 138 ms, submit 1120 ms
submitted   14:10:59 UTC
TOTAL       2.42 s (client side)
result      CORRECT   flag 5b8c7b3e…9928

Mastery

Started straight after the Time Trial. One submit of 1,506 answers, twice the Single Solve's 753 (Day 9's Mastery was five times).

started_at  2026-10-10T14:11:03.651Z   deadline (not in the request log)
coverage    1,506/1,506, one submit
timings     start 1132 ms, artifact 745 ms, solve 309 ms, submit 1227 ms
submitted   14:11:06 UTC
TOTAL       3.41 s (client side)
result      CORRECT   flag 001afc05…7304

Both correct on the first attempt.

Time to solve

The solver started the Single Solve at 13:00:09 UTC and had 747 of 753 answers accepted by 13:00:21, when an HTTP 429 stopped it; the last six went in by hand at 14:10:48 for the CORRECT. The Time Trial (2.42 s) and Mastery (3.41 s) followed on the first attempt each, for 1 h 11 min from the first start to the last CORRECT, under half a minute of it spent submitting.

Takeaways

  • The unattended morning worked. The scheduled solver fired, found the list at 9:00, and had 747 of 753 answers accepted within 12 s of the start, with no human in the loop.
  • Pace the submits. The add-ons sent many tiny submits back to back, and the Game Master throttled them. One second between submits fixes it without slowing a timed run, which sends a single submit.
  • Stop on 429 was the right rule. The solver didn't retry or guess, so nothing was lost: the six open answers were simply sent later.
  • Compounding pays off. Day 9's chain, with the control and expansion rules found the night before, answered a new host type (WMI MOF) and two new Bash fixtures with no change.
  • A prompt can promise more than the questions ask. The bindings and "the subscription" aren't questions here. Check the question list before building for the prompt.