The challenge
"A Jenkins Pipeline splits its Groovy stages between controller and agent, and not every step runs where it appears to. Recover the pipeline's intent, separate controller semantics from agent semantics, and trace the modeled build into its prior-language stages."
Every earlier day's script fields plus 80 new ones: 1,329 questions on the Single Solve (Day 19 had 1,249; none were dropped). Written from the solver's report, the start reply's question list, and the Game Master request log; the specimens weren't reopened.
The new specimens each carried the lane's usual question family:
| answer_id (per specimen) | Question | Format |
|---|---|---|
…- |
"Classify the inert source role." | enum (benign_, downloader, dropper, impact, launcher, persistence_, relay, staged_, stager, uploader, advanced_) |
…- |
Map the decoded ordered behaviour graph to one primary ATT&CK technique, by the stated precedence | technique or sub-technique ID, or none for benign |
…-, …-, …- / …- |
Recover the modelled adapter, campaign ID, and indicator | exact text |
…- |
Recover the modelled stage count | base-10 integer |
…- |
Recover the ordered behaviour graph | tokens joined by > |
…- |
"Identify the script host or webshell source container." | exact text |
…-, …-, …- |
Encoding profile, multi-stage profile, next language in the handoff | exact text |
The two advanced Bash specimens asked role, attack, feature, primitive, campaign, stage-count, and steps.
Reading the prompt: what it said we'd need
| Clue | What it pointed to | What I did about it |
|---|---|---|
| "A Jenkins Pipeline … Groovy stages" | A new host container (jenkins_) in the Groovy language family |
Relied on the core chain's host-profile reader; it named the host with no change |
| "between controller and agent", "not every step runs where it appears to" | The steps graph and the stage profile: what the build decodes, where it writes, and what it launches |
The core chain's decoded behaviour graph gave decode_, three stages |
| "trace the modeled build into its prior-language stages" | The next- handoff, and the compounding fields from every earlier day |
All 1,249 earlier fields went in with the new ones; the Jenkins specimen hands off to batch |
| "The Butler Did It" (title) | Jenkins's logo is a butler | Confirmed the Jenkins specimen was the day's centrepiece |
Safety
Script specimens are hostile: static analysis only, on our Kali VM. The solver parses the text of the encrypted evidence.zip members; no specimen was executed and no build was run. No code excerpts are quoted here, only the answer values, with URLs defanged.
What was in the files
- Single Solve:
evidence.zip, 130,248 bytes, 145 encrypted members. The 80 new questions came from eight specimens: host-jenkins-pipeline-groovy.groovy(11 fields): rolestaged_chain, attackT1059, adapteroperation_graph, campaignGROOVY-49671532, URLhxxps://groovy-…example[.]invalid/stage, 3 stages, stepsdecode_embedded>write_file>dispatch_process, host profilejenkins_pipeline, obfuscationhex_base64, stage profilethree_stage_decode_write_launch, next languagebatch.host-classic-asp-vbscript.vbs(11): host profileclassic_asp, stepsacquire_remote>dispatch_process, 2 stages, obfuscationbase64, stage profiletwo_stage_download_execute, next languagejscript.- four Groovy polyglots,
polyglot-groovy-{benign-utility,downloader,launcher,staged-chain}.groovy(44); the staged chain hands off tovbscriptthroughfragmented_hex. - two advanced Bash specimens,
coprocess-block.shandmapfile-process.sh(14): roleadvanced_syntax, attackT1059.004, featurescoprocess_blockandmapfile_process. - Time Trial:
evidence.zip, 130,696 bytes, the same 1,329 questions. The Jenkins specimen had the same shape (same steps, obfuscation, stage profile, and next language); only the campaign ID and URL changed. - Mastery: one 649,823-byte zip, 5 sets, 6,645 questions. All five Jenkins specimens matched the Single Solve's shape with their own campaign IDs.
Single Solve
The solver solved it with no stop. It picked up today's challenge ID with its core script solver, which uses the split-header reader added on Day 19, and sent two batches:
- Core batch, 1,200 answers →
accepted, 129 remaining. All 80 new fields were in it. The solver flagged 50 values it had seen rejected on other questions before (mostlynoneandT1105attack values) and sent them anyway, as it is set to; none was rejected here. - Merged add-on batch, 129 answers → CORRECT. These were the fields the solver's add-on readers own: 72 JScript, 16 Batch, 8 VBScript, and 11 each for the WSF, HTA, and SCT hosts.
started_at 2026-10-20T13:00:51.412Z
deadline none (Single Solve)
answers 1,200 (core) + 129 (add-ons merged) = 1,329
start / artifact / solve timings: not recorded for the Single Solve
core submit 13:00:52 → 13:00:52 accepted, remaining 129
add-ons submit 13:00:53 → 13:00:54
TOTAL ~3 s from the start reply to CORRECT (log precision)
result CORRECT flag 732ce083…3b5d
No new solver, tests, or rehearsal were written today: the code that ran was the same as on Day 19.
Time Trial
CORRECT on the first attempt, ranked (50 s clock, 1,329 answers).
started_at 2026-10-20T13:01:00.518Z
deadline 2026-10-20T13:01:50.518Z (50 s)
answers 1329
start 598 ms
artifact 414 ms
solve 80 ms
submit 1050 ms
TOTAL 2144 ms (submit +1.82 s after started_at)
result CORRECT flag 26feaa47…5a05
Mastery
CORRECT on the first attempt, ranked (5 sets, 170 s clock).
started_at 2026-10-20T13:01:07.889Z
deadline 2026-10-20T13:03:57.889Z (170 s)
answers 6645 across 5 sets
start 930 ms
artifact 700 ms
solve 412 ms
submit 1727 ms
TOTAL 3778 ms (submit +3.46 s after started_at)
result CORRECT flag 709dc3de…7a13
Time to solve
All three modes were solved by 09:01:11 ET, 21 s after the solver's first start request at 09:00:50 ET. The Single Solve took two batches about 3 s apart, and the ranked Time Trial and Mastery each went through on the first submit.
Takeaways
- The general reader keeps paying off. A new host (Jenkins Pipeline), a new language family (Groovy), and classic ASP all went through the existing chain with no code change, for the second day running.
- The rejected-before warning is advice, not a stop. 50 values we had seen rejected elsewhere were right for these questions; the solver sends them and lets the Game Master judge.
- Mastery is the slow part. 6,645 answers took 1.7 s to submit; the solve itself was 412 ms.