I finished 3rd in MANU Protocol / The Last Dataset. What stays with me is how often the decisive evidence sat one layer away from the obvious answer: a public replay started two minutes after the real event, a 1.38-second recording pointed to a lighthouse, and a repository with a thousand commits never changed its files.

The event connected a fictional fractured registry, failed communications, archive tampering, and a dataset-recovery objective. Progress meant recovering evidence across colored zones, submitting flags, and unlocking fragments of the larger dataset. The story supplied both context and dependencies: an operator’s handle became a cipher key, a protocol name unlocked a feature manifest, and an accepted signal reference opened an archive record.

This retrospective follows the detailed notes preserved from the 15 October 2026 session. It documents ten flags, the Community, Radio, and Orange trails, and the reasoning behind each accepted result. My overall placement was third; the 1,300 points and 3/4 dataset fragments shown later are an intermediate checkpoint, not a final score. The notes do not preserve every stage of the competition, so the missing Red, Purple, and final submission details remain explicit gaps.

Spoilers: accepted flags, puzzle answers, and extraction code follow. Challenge names, artwork, and screenshots belong to their respective event creators. AI assistance supported browser operation, scripting, signal analysis, and organizing the investigation; I supplied context, evidence, and decisions throughout the solve.

Recorded results

ChapterChallengeOutcomeAccepted flag
01SanctuaryRecovered before the detailed notes began; later hub completion confirmedMANU{the_registry_remembers}
02Community / YellowAccepted; Community clearedFLAG{CONTINUITY_841_0217_UNIT404}
03Radio CTF 01: Communication TerminalAcceptedBLUEZONE{BLACKOUT-17}
04Radio CTF 02: Relay Network MapAcceptedBLUEZONE{SILENT_RELAY}
05Radio CTF 03: Voice ArchiveAcceptedBLUEZONE{NORTHLIGHT}
06Radio CTF 04: Signal MonitorAccepted; Blue clearance later confirmedBLUEZONE{KAPU_LIGHTHOUSE}
07Orange SEC-01: Vault BreachAcceptedMANU{t1m3st4mp_l5b_h1dd3n_1n_pl41n_s1ght}
08Orange SEC-02: Who Edited This?AcceptedMANU{ROHAN_0335}
09Orange SEC-03: Sealed FeaturesAcceptedMANU{AGE_SLEEP_SKILL_STRESS_FOCUS}
10Orange SEC-04: Hash MismatchAccepted; Orange convergence confirmedMANU{ration_audit.csv_7dfdbe62}

The last hub checkpoint preserved in these notes was 1,300 points and 3/4 recovered dataset fragments, with Yellow, Blue, and Orange cleared and Red available. That is an intermediate session checkpoint, not my final competition score or the basis for reconstructing the final leaderboard.

Sanctuary: the registry remembers

Category: opening narrative / registry checkpoint
Recorded flag: MANU{the_registry_remembers}
Evidence strength: recovered before the detailed notes began, corroborated by subsequent hub completion.

What is actually preserved

Sanctuary had already been completed when this session began. I had already recovered the flag; later hub state confirmed that the opening checkpoint had been cleared.

The surviving notes do not contain the original puzzle screen, the exact clues leading to the phrase, or a command-by-command solve. It would be inaccurate to invent a hidden file, an endpoint, a cipher, or a particular search that supposedly produced it.

Lesson

Acceptance and derivation are different kinds of evidence. We can substantiate that the checkpoint was completed without pretending to have a detailed record of its solution.

Community / Yellow: reconstructing the Continuity ledger

Category: evidence correlation / timeline reconstruction
Accepted flag: FLAG{CONTINUITY_841_0217_UNIT404}
Outcome: CONTINUITY LEDGER RECOVERED, +200 points, BLUE UNLOCKED; total score 300.

The problem

The answer was distributed across several locations. Instead of decoding one file, we had to establish four fields from independent records and assemble them in the correct order.

The intended route was:

Hospital → School → Museum → Sports Complex → Society.

That distinction matters: the route used to discover evidence was not the ordering of fields inside the flag.

Step 1: recover the answer schema

The School artifact NA-H1 established:

DATASET_ID → CYCLE → EVENT_TIME → SOURCE_NODE

It also specified that EVENT_TIME used HHMM, excluding seconds.

This gave us a schema before we selected values. A clue that looked important was not automatically the answer; it had to fit one of these four fields.

Step 2: identify the dataset and cycle

Museum artifact GW-H1 established DATASET_ID as CONTINUITY and the cycle tag as C-841.

There was also a tempting label, CI-841 / Continuity Index. Museum note RF-N1 clarified that CI was an archive category. We therefore did not substitute the category abbreviation or the public exhibit title for the dataset identifier.

The selected values were:

  • DATASET_ID = CONTINUITY
  • CYCLE = 841

Step 3: distinguish the original event from the public replay

Hospital record AH-S1 showed a printer job accepted at 02:17:06 SZT. Another record, SW-S1, showed occupied at 02:17 and EMPTY at 02:19. Paper intake H-017 survived even though the public terminal displayed EMPTY.

Sports artifact SL-P1 independently recorded:

EvidenceTime
Raw event, cycle 84102:17:06
Public replay begins02:19:00

The public replay time was later than the underlying event. The hospital and sports records agreed on the earlier time, so we used the raw event rather than the replay.

Applying the School's formatting rule:

02:17:06 → 02:17 → 0217

We dropped seconds; we did not round to the next minute.

Step 4: recover the actual source node

Society artifact U4-P1 showed a door plate numbered 404 beside a utility panel with the live service address UNIT404.

The public directory listed only units 401–403. That contradiction mattered because it showed that a missing public entry did not mean the service location did not exist.

The required field was SOURCE_NODE. UNIT404 was the service address; 404 alone was only the door plate number.

Step 5: assemble and submit

FieldValueSupporting evidence
DATASET_IDCONTINUITYMuseum GW-H1; RF-N1 disambiguates CI
CYCLE841Museum cycle tag; Sports raw event
EVENT_TIME0217Hospital 02:17:06; Sports raw event; School HHMM rule
SOURCE_NODEUNIT404Society service address

The resulting flag was:

FLAG{CONTINUITY_841_0217_UNIT404}

My screenshot confirmed acceptance, the +200-point award, and Blue's unlock. Subsequent hub state was consistent with that result.

What we did not infer

Society note SD-P1 said 18 identity rows had been removed from the public registry but retained in a reconciliation ledger. Those 18 rows explained a story discrepancy. They did not establish the recovered CSV's row count or anyone's survival outcome.

The recovered community_final.csv had 120 records and 20 columns, with unique Sanctuary_ID values. It also contained textual missing-value markers such as Not Logged. That file was preserved without treating every nonempty string as complete data.

Why this worked

The decisive move was to separate the answer's structure from its contents. Once we had the four-field schema, each location became evidence for a specific value. Independent timestamps resolved the strongest ambiguity.

Radio CTF 01: finding BLACKOUT-17

Category: in-world OSINT / provenance comparison
Accepted flag: BLUEZONE{BLACKOUT-17}
Acceptance record: earlier browser acceptance and my screenshots; the station remained verified in this session.

The problem

Communication Terminal TRANSMISSION_07 contained five fragments initially out of sequence. The recovered operator instructions described a node name made from two pieces:

  1. A word from a hashtag on the operator's original tower photograph on the blackout night.
  2. A tower registry number.

The operator also ruled out the other tower photograph and the rail-bridge mast. The relay was surviving on battery power.

We needed a provenance-based identification, not whichever tower image looked most plausible.

Step 1: identify the original photograph

The relevant profile handle was echo_afterfall.

PropertyOriginal photo ACompeting photo B
File identityIMG_0214_2341_A.RAWSaved from another upload
Capture metadataDay 214, 23:38Missing
Post time23:41Not the deciding evidence
ProvenanceOriginal handset imageRe-uploaded/saved image
Tank shapeCylindrical tank on legsSpherical tank
BeaconRedWhite

The original had an eight-second exposure and the caption:

lights are finally back. #blackout

The requested word was therefore BLACKOUT.

Capture time and post time were separate facts. The question referred to the operator's original photograph, so provenance and matching physical features were more important than simply choosing a recent post.

Step 2: correlate physical features with the registry

The archive described:

  • RLY-17 = WATER TANK ARRAY // EAST.
  • East bank, across the river, behind a cylindrical water tank.
  • Red blinking beacon.
  • Intermittent battery power.
  • Volunteer operator registered to SANC-0003.

The cylindrical tank, red beacon, and battery behavior matched photo A and the transmission's constraints. The registry number was 17.

Step 3: construct the node name

BLACKOUT + 17 → BLACKOUT-17

Submission:

BLUEZONE{BLACKOUT-17}

Step 4: recover the next puzzle's key

The accepted handoff contained:

XRL: GUR UNAQYR, JVGUBHG GUR RPUB

ROT13 decoded it to:

KEY: THE HANDLE, WITHOUT THE ECHO

A small reproduction:

import codecs
 
text = "XRL: GUR UNAQYR, JVGUBHG GUR RPUB"
print(codecs.decode(text, "rot_13"))

The profile handle was echo_afterfall. Removing the echo component and its separator left:

afterfall

That word became the Vigenère key for CTF 02.

False leads and lessons

The competing photograph was not irrelevant decoration: it was a plausible wrong source. Its missing capture metadata, different tank shape, and different beacon color prevented it from satisfying all the operator's conditions.

The method was to require several independent matches before accepting a source. A correct-looking hashtag on the wrong photograph would still have been wrong evidence.

Radio CTF 02: Base64 transport and a Vigenère relay packet

Category: layered decoding / classical cryptography
Accepted flag: BLUEZONE{SILENT_RELAY}
Verified route: SANC-0002 → SANC-0034.

The problem

The Network Map's NODE-17 exposed a packet and a SEND PACKET TO WORKBENCH control. The framing described Base64 transport around Vigenère-encrypted text.

The key had already been established by CTF 01:

afterfall

This was a dependency between challenges, not a password we needed to brute-force.

Step 1: remove the outer transport encoding

The intended workstation sequence was:

  1. FROM BASE64
  2. USE AS INPUT
  3. VIGENÈRE DECODE, key afterfall

Base64 supplied a transport representation. Decoding it did not, by itself, decrypt the inner message.

Step 2: apply the cipher's precise rule

For letters represented as A=0 through Z=25:

P[i] = (C[i] - K[j]) mod 26

The challenge applied the cipher only to letters A–Z. Other characters passed through unchanged. The key advanced when a letter was processed, rather than advancing for spaces, punctuation, digits, or braces.

That rule matters for a message containing identifiers such as SANC-0002 and a flag with underscores.

The cleaned helper below preserves the nonletters. The original packet ciphertext was not retained in our notes; this is the decoding method, not a claim that the exact historical packet is bundled here.

# script: radio02_decode_packet.py
import base64
import sys
from pathlib import Path
 
 
def vigenere_decode(text, key):
    key = key.upper()
    shifts = [ord(c) - ord("A") for c in key]
    if not shifts or any(not 0 <= k < 26 for k in shifts):
        raise ValueError("Key must contain only A-Z letters")
    result = []
    key_position = 0
    for c in text.upper():
        if "A" <= c <= "Z":
            shift = shifts[key_position % len(shifts)]
            result.append(chr((ord(c) - ord("A") - shift) % 26 + ord("A")))
            key_position += 1
        else:
            result.append(c)
    return "".join(result)
 
 
if __name__ == "__main__":
    encoded = "".join(Path(sys.argv[1]).read_text().split())
    ciphertext = base64.b64decode(encoded, validate=True).decode("ascii")
    print(vigenere_decode(ciphertext, "afterfall"))

Usage, if you have the original packet saved separately:

python scripts/radio02_decode_packet.py packet_base64.txt

Step 3: interpret the plaintext

The recovered message was:

ECHO TO ANY OPERATOR STILL LISTENING. THE BLACKOUT WAS NO STORM. THE RELAYS DID NOT FAIL - THEY WERE TRIPPED. NEXUS SANC-0002 STILL ROUTES TO GATEWAY SANC-0034. MY LAST LOGS RIDE THE FAILED HANDSHAKE CHANNEL. CONFIRM ROUTE: BLUEZONE{SILENT_RELAY}

The message supplied both the flag and a concrete route:

SANC-0002 → SANC-0034

It also pointed toward failed handshake evidence, which became relevant later.

Acceptance and lesson

The earlier acceptance record showed CTF 02 SOLVED, and the Network Map remained verified in our session.

The useful pattern was to work outside-in: remove the transport layer, then apply the known cipher using the key's exact advancement rule. Readable output alone was not the final checkpoint; the designated submission confirmed acceptance.

Radio CTF 03: Morse audio and the North Tower archive

Category: signal analysis / archive lookup
Accepted flag: BLUEZONE{NORTHLIGHT}.

The input

The event supplied va-07.65b9c55b.wav:

PropertyValue
Encoding16-bit PCM WAV
ChannelsMono
Sample rate48,000 Hz
DurationApproximately 27.457 seconds
Relevant carrier700 Hz keyed tones

This is the Voice Archive recording. It is a different file from the 1.38-second SIG-03 DTMF intercept used in CTF 04.

Step 1: measure the tone's on/off timing

Instead of treating the audio as speech, the original analysis measured the strength of a 700 Hz component in 10-millisecond windows.

A complex sinusoid at 700 Hz acts as a narrow frequency probe. Multiplying each audio window by that probe and taking the magnitude gives a time series indicating when the target tone is present.

Thresholding that series gives tone bursts separated by silence.

Step 2: translate timing into Morse symbols

For this particular recording, the original script used:

  • Ignore bursts shorter than 0.03 seconds.
  • Burst longer than 0.14 seconds → dash; otherwise → dot.
  • Gap longer than 0.20 seconds → end the current Morse letter.
  • Gap longer than 0.50 seconds → also insert a word space.

Those values were tuned to this artifact. They are not universal Morse timing constants for every recording.

The cleaned reproduction preserves the original detector:

# script: radio03_decode_morse.py
import sys
import wave
from pathlib import Path
 
import numpy as np
 
 
def decode(path):
    with wave.open(str(path), "rb") as wav:
        if wav.getsampwidth() != 2:
            raise ValueError("This reproduction expects 16-bit PCM")
        rate = wav.getframerate()
        channels = wav.getnchannels()
        samples = np.frombuffer(
            wav.readframes(wav.getnframes()), dtype="<i2"
        ).astype(float)
    samples = samples.reshape(-1, channels).mean(axis=1)
    window = int(rate * 0.01)
    frames = samples[:len(samples) // window * window].reshape(-1, window)
    probe = np.exp(-2j * np.pi * 700 * np.arange(window) / rate)
    energy = np.abs(frames @ probe) / window
    active = energy > np.quantile(energy, 0.95) * 0.35
    changes = np.flatnonzero(np.diff(np.r_[False, active, False]))
    bursts = [
        (round(a * 0.01, 2), round(b * 0.01, 2), round((b-a) * 0.01, 2))
        for a, b in changes.reshape(-1, 2)
        if (b-a) * 0.01 >= 0.03
    ]
    codes = dict(zip(
        ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- "
        "-. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --..".split(),
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
    ))
    message, symbol = "", ""
    for i, (_, end, duration) in enumerate(bursts):
        symbol += "-" if duration > 0.14 else "."
        gap = bursts[i+1][0] - end if i+1 < len(bursts) else 10
        if gap > 0.20:
            message += codes.get(symbol, "[" + symbol + "]")
            symbol = ""
            if gap > 0.50:
                message += " "
    return message.strip()
 
 
if __name__ == "__main__":
    print(decode(Path(sys.argv[1])))

Usage:

python scripts/radio03_decode_morse.py va-07.65b9c55b.wav

Result:

THE LAST SIGNAL CAME FROM THE NORTH TOWER

Step 3: use the message as a pointer, not as the flag

The Morse sentence told us which archive to consult. The North Tower NT-04 log contained these days:

Log dayChannel-buffer character
203N
205O
208R
210T
211H
213L
215I
217G
218H
219T

Reading the corresponding characters in that order produced:

NORTHLIGHT

Submission:

BLUEZONE{NORTHLIGHT}

Acceptance and lesson

The prior session recorded CTF 03 SOLVED, and the Voice Archive remained verified when we resumed.

This was a two-stage solution: the audio identified an archive; the archive supplied the actual flag text. Solving this independent station did not, on its own, advance the main investigation counter beyond 2/3.

Radio CTF 04: six keypad tones lead to Kapu Lighthouse

Category: DTMF decoding / log correlation / coordinate lookup
Accepted flag: BLUEZONE{KAPU_LIGHTHOUSE}
Outcome: CTF 04 SOLVED and NAVIGATION TARGET CONFIRMED; Blue later shown cleared in the main hub.

The problem

Signal Monitor RF-SPEC-03 listed five short intercepts. Its analysis tab reported six dual-frequency bursts, roughly 180 milliseconds long, with structured spacing and possible keypad signalling.

The critical question was which intercept had actually caused a controller to execute and file a command.

Step 1: select the intercept from the transmission log

SignalCarrierCaptureRelevant controller outcome
SIG-01142.85 MHz21:52:10Clinic exchange had no answer; line unpowered
SIG-02156.30 MHz22:41:18Emergency repeater rejected the command after lockout
SIG-03151.40 MHz22:07:29EAST ARRAY accepted the remote command at 22:07:31
SIG-04168.95 MHz21:31:05Scheduled maintenance pager test; no relay action
SIG-05143.70 MHz22:15:44Damaged capture; no controller response

The grid failed at 21:40, and the emergency repeater entered lockout at 21:40:02. That made its later rejected command a different trail from the successfully executed EAST ARRAY command.

We selected SIG-03, not the easiest-looking recording or the signal whose frequency appeared in the separate carrier-lock task.

Step 2: obtain the exact recording

The selected recording was intercept-03.55b4f5c0.wav, supplied by the event at:

Original challenge resource

I downloaded the exact event-provided WAV for local analysis, preserving its original bytes.

The supplied file was:

  • 44,100 Hz, mono, 16-bit PCM.
  • 1.38 seconds long.
  • SHA-256: d446961bec85750a992ed5842bf53d0d8a71a9739a6a39165a012023c64bfa35.

Step 3: identify DTMF frequency pairs

DTMF combines one low-frequency row tone and one high-frequency column tone for each key.

Low / high1209 Hz1336 Hz1477 Hz1633 Hz
697 Hz123A
770 Hz456B
852 Hz789C
941 Hz*0#D

We segmented the audio using short-window RMS energy, discarded each burst's edges, applied a Hann window, and measured its frequency spectrum.

For each burst, we selected the strongest expected low-row frequency and strongest expected high-column frequency. We used a small frequency tolerance because finite FFT windows place measured peaks near, rather than necessarily exactly on, nominal DTMF frequencies.

BurstApproximate startLow toneHigh toneDigit
10.0000 s852 Hz1209 Hz7
20.2295 s697 Hz1477 Hz3
30.4590 s697 Hz1209 Hz1
40.6884 s697 Hz1336 Hz2
50.9179 s941 Hz1336 Hz0
61.1474 s770 Hz1209 Hz4

The reference was 731204.

# script: radio04_decode_dtmf.py
import sys
import wave
 
import numpy as np
 
 
def decode(path):
    with wave.open(str(path), "rb") as wav:
        if wav.getsampwidth() != 2:
            raise ValueError("This reproduction expects 16-bit PCM")
        rate, channels = wav.getframerate(), wav.getnchannels()
        samples = np.frombuffer(
            wav.readframes(wav.getnframes()), dtype="<i2"
        ).astype(float)
    samples = samples.reshape(-1, channels).mean(axis=1) / 32768
    hop = max(1, round(rate * 0.005))
    rms = np.array([
        np.sqrt(np.mean(samples[i:i+hop] ** 2))
        for i in range(0, len(samples), hop)
    ])
    edges = np.diff(np.r_[False, rms > rms.max() * 0.2, False].astype(int))
    starts, stops = np.flatnonzero(edges == 1), np.flatnonzero(edges == -1)
    low, high = [697, 770, 852, 941], [1209, 1336, 1477, 1633]
    keypad, digits = ["123A", "456B", "789C", "*0#D"], []
    for start, stop in zip(starts, stops):
        a, b = start * hop, min(stop * hop, len(samples))
        if (b-a) / rate < 0.05:
            continue
        margin = round(rate * 0.015)
        x = samples[a+margin:b-margin]
        x = x * np.hanning(len(x))
        frequencies = np.fft.rfftfreq(len(x), 1 / rate)
        spectrum = abs(np.fft.rfft(x))
 
        def strength(tone):
            return float(spectrum[abs(frequencies-tone) < 15].max())
 
        row = max(range(4), key=lambda i: strength(low[i]))
        col = max(range(4), key=lambda i: strength(high[i]))
        digit = keypad[row][col]
        print(f"{low[row]} + {high[col]} Hz -> {digit}")
        digits.append(digit)
    return "".join(digits)
 
 
if __name__ == "__main__":
    print("Reference:", decode(sys.argv[1]))

Step 4: retrieve the filed record

Under Evidence → Archive Index, we entered 731204 and used RETRIEVE.

The returned record corroborated the signal selection:

  • COMMAND: 731204
  • STATUS: EXECUTED
  • SOURCE: EAST ARRAY // 151.40 MHz
  • FILED: DAY 214 22:07:31

The recovered navigation packet contained:

LAT 13.2239132
LON 74.7367936
REFERENCE COASTAL RELAY

The appended field note said:

WHEN THE NETWORK GOES DARK, FOLLOW THE LIGHT.

Step 5: identify the actual destination

We followed the challenge's own external map link. The coordinates landed on the Kapu coast. Looking up the nearby lighthouse in that same map established the place as Kapu Light House, also represented by the spelling Kaup Light House.

A map result placed Kapu Light House at approximately 13.2239492, 74.7367974, consistent with the recovered endpoint.

The flag format joined place-name words with underscores:

BLUEZONE{KAPU_LIGHTHOUSE}

Acceptance

The site displayed CTF 04 SOLVED, NAVIGATION TARGET CONFIRMED, COASTAL RELAY IDENTIFIED, and CTF 04 COMPLETE.

Radio CTF 04 shows navigation target confirmed and CTF complete

Signal Monitor confirms the navigation target after the Kapu Lighthouse flag was accepted.

The main hub subsequently showed Blue cleared, 700 total points, 2/4 dataset fragments, and radio_final.csv available. We recovered that file through the hub vault.

What made this puzzle work

There were three independent joins:

  1. Capture timestamp and frequency → accepted controller event.
  2. Decoded keypad reference → matching executed archive record.
  3. Coordinates and lighthouse clue → a named destination.

Frequency alone was insufficient. The separate 156.30 MHz carrier-lock step did not identify the navigation intercept.

Orange SEC-01: hiding a flag in 1,000 git timestamps

In-game title: The Nightly Archive Sync / Vault Breach
Category: git forensics / metadata steganography
Accepted flag: MANU{t1m3st4mp_l5b_h1dd3n_1n_pl41n_s1ght}.

The problem

The briefing described a terminal purge at 03:14:40 UTC on the breach night, 17 September 2026. A sync daemon had mirrored the Civic Transfer Registry to an archivist workstation. The recovered artifact was a repository with a 1,000-commit logbook.

The event explicitly supplied:

Original challenge resource

We cloned the repository with its full history. A shallow clone would have discarded most of the evidence.

git clone --no-checkout https://github.com/Hritik-1810/Orange_zone_archieve.git Orange_zone_archieve
git -C Orange_zone_archieve rev-list --count HEAD
git -C Orange_zone_archieve ls-tree -r --long HEAD
git -C Orange_zone_archieve log -12 --format="%h %ad %s" --date=iso-strict

The saved repository's HEAD was:

42c38ac15974e004f136f01837de1234a2e041ba

Step 1: rule out ordinary deleted-file recovery

The current tree contained:

  • README.md, describing a Nightly Archive Sync Log.
  • sync.conf, containing nodes=1..5 mode=incremental tz=utc.

We inspected file changes and searched history for flag-like content. The decisive result was that all 1,000 commits referenced the same tree.

That made a conventional “someone deleted the flag from a file” explanation unlikely for this artifact. It did not mean the history contained no information: commit metadata can vary even when the tree does not.

Step 2: notice the timestamp pattern

The commit subjects were repetitive sync operations with numbered cycles. The seconds component of the timestamps was consistently 02 or 03.

Examples from the beginning:

CommitTimestampMeaning
Initialization2026-09-17 02:14:02 UTCCreates the log's starting state
sync cycle #02026-09-17 03:14:02 UTCFirst numbered sync event
rotate buffer #12026-09-17 03:15:03 UTCNext numbered event
refresh cache #22026-09-17 03:16:02 UTCNext numbered event

The 02/03 variation suggested one-bit storage:

timestamp & 1

  • An even epoch timestamp contributes 0.
  • An odd epoch timestamp contributes 1.

Because a minute contains an even number of seconds, the parity of the full epoch timestamp agrees with the parity of the seconds component here.

Step 3: preserve ordering and byte alignment

Git's default log order is newest first. The embedded message needed the opposite direction: oldest sync event to newest.

There was also a non-payload initialization commit. Including it prepended an extra bit and shifted the byte boundaries.

The original exploratory script tested both timestamp columns, whether to skip the initialization entry, and bit offsets. The successful extraction skipped the initializer and grouped the remaining bits into eight-bit bytes, most significant bit first.

The first byte illustrates the hypothesis:

01001101 → 0x4d → M

The decoded bytes began with MANU{...}; the bytes after the closing brace were not needed as part of the flag.

Reproduction

This version validates that the oldest entry is the expected initializer rather than silently discarding an arbitrary first commit.

# script: orange01_git_lsb.py
import re
import shutil
import subprocess
import sys
 
 
def recover(repo, git="git"):
    def run(*args):
        return subprocess.check_output(
            [git, "-C", str(repo), *args], text=True
        ).splitlines()
 
    rows = [
        line.split("|", 1)
        for line in run("log", "--reverse", "--format=%at|%s", "HEAD")
    ]
    trees = run("log", "--format=%T", "HEAD")
    print("Commits:", len(rows))
    print("Unique trees:", len(set(trees)))
    if rows[0][1] != "chore: init sync log":
        raise ValueError("Unexpected history; inspect before choosing alignment")
    timestamps = [int(timestamp) for timestamp, _ in rows[1:]]
    bits = "".join(str(timestamp & 1) for timestamp in timestamps)
    decoded = bytes(
        int(bits[i:i+8], 2) for i in range(0, len(bits)-7, 8)
    )
    match = re.search(rb"MANU\{[^}\r\n]+\}", decoded)
    if match is None:
        raise ValueError("No MANU flag found with this alignment")
    return match.group().decode("ascii")
 
 
if __name__ == "__main__":
    git = sys.argv[2] if len(sys.argv) > 2 else shutil.which("git")
    if not git:
        raise SystemExit("Pass a git executable as the second argument")
    print(recover(sys.argv[1], git))

Usage:

python scripts/orange01_git_lsb.py Orange_zone_archieve

Output:

Commits: 1000
Unique trees: 1
MANU{t1m3st4mp_l5b_h1dd3n_1n_pl41n_s1ght}

Acceptance

We submitted the recovered flag in SEC-01's SUBMIT FLAG form. The site marked the sector cleared, showed FLAG VERIFIED, and unlocked the SANC-0001–SANC-0030 fragment.

Orange SEC-01 marked cleared with the first archive fragment unlocked

The timestamp bitstream flag unlocks fragment 1, covering SANC-0001–SANC-0030.

Why it was the strongest Orange puzzle

The interesting step was changing the unit of investigation. We began with file contents and diffs; once those were constant, the meaningful variation was in the commits themselves.

The 1,000 commits were not 1,000 separate puzzles. They were a bitstream with a recognizable structure.

Orange SEC-02: identifying a PDF editor and the exact UTC minute

In-game title: Fragment Seal 047 Certificate / Who Edited This?
Category: document provenance / PDF metadata
Accepted flag: MANU{ROHAN_0335}.

The problem

Two copies of a Council sealing certificate were provided:

  • sealing_certificate_original.pdf
  • sealing_certificate_edited.pdf

The task asked who edited the certificate and when. Its output contract was precise:

MANU{NAME_HHMM}

NAME meant the editor's first name in uppercase. HHMM meant the modification time in UTC, using a 24-hour clock and dropping seconds.

The chain-of-custody note warned against re-saving, printing to PDF, or using Save As. Those operations could replace exactly the metadata we needed.

Step 1: read both files without rewriting them

We downloaded the original files and inspected them with pypdf. No PDF writer was used, and neither input was re-saved.

The original metadata included:

Author:       MANU Archive Council
CreationDate: D:20260801100000Z
ModDate:      D:20260801100000Z
Creator:      MANU Seal Generator 2.1
Producer:     MANU Seal Generator PDF Core

The edited copy included:

Author:       Rohan Desai
CreationDate: D:20260801100000Z
ModDate:      D:20260917033512Z
Creator:      MANU Seal Generator 2.1
Producer:     ScribeForge PDF Studio 9

Step 2: distinguish creation, modification, and approval

The CreationDate was unchanged. The ModDate identified a later alteration:

D:20260917033512Z → 2026-09-17 03:35:12 UTC

The Z explicitly indicates UTC. We did not convert this to my local time.

The visible approval line named Dr. Ilan Verma, Chair of the Archive Council. That was an approver in the certificate body, not the edited file's Author property. We did not substitute the approver for the requested editor.

The Producer change supplied additional provenance evidence: the edited file had passed through a different PDF program.

Metadata can be forged in real investigations. Here it was the event-provided evidence channel, supported by a comparison between the two artifacts; it was not independent proof of a real person's authorship outside the CTF.

Step 3: corroborate the change in the page content

The text also changed:

FieldOriginalEdited
RECORDS SEALED450405

The certificate otherwise retained the same identifying structure and approval language. Comparing content alongside metadata established what the modified copy changed, rather than reading a name in isolation.

Reproduction

# script: orange02_pdf_editor.py
import sys
from datetime import timezone
 
from pypdf import PdfReader
 
 
def inspect(original_path, edited_path):
    original = PdfReader(original_path)
    edited = PdfReader(edited_path)
    for label, reader in (("ORIGINAL", original), ("EDITED", edited)):
        metadata = reader.metadata
        print(label)
        for key in ("/Author", "/CreationDate", "/ModDate", "/Producer"):
            print(f"  {key}: {metadata.get(key)}")
    modified = edited.metadata.modification_date
    if modified is None or modified.tzinfo is None:
        raise ValueError("Modification date must include a timezone")
    editor = edited.metadata.author.split()[0].upper()
    hhmm = modified.astimezone(timezone.utc).strftime("%H%M")
    return f"MANU{{{editor}_{hhmm}}}"
 
 
if __name__ == "__main__":
    print(inspect(sys.argv[1], sys.argv[2]))

Usage:

python scripts/orange02_pdf_editor.py sealing_certificate_original.pdf sealing_certificate_edited.pdf

Step 4: apply the format

Rohan Desai → ROHAN
03:35:12 UTC → 0335

Submission:

MANU{ROHAN_0335}

The server accepted it and unlocked the SANC-0031–SANC-0060 fragment.

Orange SEC-02 marked cleared with the second archive fragment unlocked

The PDF provenance answer unlocks fragment 2, covering SANC-0031–SANC-0060.

Lesson

The answer was in the file's properties, not in a difficult cryptographic transformation. The useful discipline was selecting the correct person and the correct timestamp field, then obeying the timezone and seconds rule exactly.

The approval line describes an in-world role; the edited artifact’s Author field answers a different question.

Orange SEC-03: a PNG carries a Vigenère feature manifest

In-game title: The Sealed Feature Manifest / Sealed Features Vault
Category: image steganography plus classical cryptography
Accepted flag: MANU{AGE_SLEEP_SKILL_STRESS_FOCUS}.

The problem

The Council had sealed the list of signals read by its survival model. We needed five feature names, in plate order:

MANU{FEATURE_FEATURE_FEATURE_FEATURE_FEATURE}

The instructions specified uppercase words joined by underscores and allowed a trailing padding X to be ignored.

The evidence consisted of a Council memo, an edge inscription, and the original sealed_plate.png.

Step 1: separate the real objective from plausible decoys

The edge inscription was:

YNFGQNGN{NTR_ANZR_VQ_OYBBQTEBHC}

ROT13 turns that into:

LASTDATA{AGE_NAME_ID_BLOODGROUP}

It looked flag-shaped, but it used a different prefix and did not match the requested five-feature structure. The evidence also warned that not every cipher-looking string was the sealed message.

The picture itself displayed a zombie-apocalypse flag. We did not submit either visible candidate simply because it looked like a flag.

These observations did not, by themselves, prove where the real message was. They told us to continue examining the actual image artifact.

Step 2: inspect metadata and channel structure

The original image was:

  • PNG, 2752 × 1536 pixels.
  • RGBA.
  • No useful Pillow metadata entries.
  • Alpha channel fixed at 255.

The constant alpha channel made it uninteresting as a lowest-bit payload in this file. The RGB channels were still candidates.

The exploratory script tried individual channels, RGB, RGBA, and both byte-packing bit orders. The useful output was in RGB least significant bits, in row-major pixel order, packed most significant bit first.

The extraction order was:

top-left pixel R, G, B → next pixel R, G, B → ... → next row

For each channel value:

bit = channel_value & 1

Changing that bit changes an 8-bit channel value by at most one, which explains why a message can coexist with an apparently normal picture.

Step 3: extract the ciphertext

The decoded stream began:

PXEDL CEEJK TLJSI IEDSD ORLSI

The text after that was not needed for this message. We had found a structured ciphertext, not yet the final feature list.

Step 4: derive the key from the event's own memo

The memo stated:

  • A seal never carries its own key.
  • Every plate uses one uppercase word: the name of the protocol that ordered the shattering.

The founding story identified that protocol as:

PRALAYA

This was not a guessed dictionary key. It was a key recovered from the puzzle's narrative dependency.

Step 5: decode and segment the plaintext

Using Vigenère decryption, with spaces removed from the ciphertext and the key repeated over letters:

AGESLEEPSKILLSTRESSFOCUSX

The five requested features could be read in order:

AGE / SLEEP / SKILL / STRESS / FOCUS

The final X was padding under the challenge's explicit rule.

The segmentation into words was a human interpretation of the readable plaintext. The cipher did not insert underscores for us.

Reproduction

# script: orange03_sealed_features.py
import re
import sys
 
import numpy as np
from PIL import Image
 
 
def recover(path):
    with Image.open(path) as image:
        rgb = np.asarray(image.convert("RGB"))
    bits = (rgb.reshape(-1) & 1).astype(np.uint8)
    payload = np.packbits(bits, bitorder="big").tobytes()
    match = re.match(rb"[A-Z]+(?: [A-Z]+){4}", payload)
    if match is None:
        raise ValueError("Expected five ciphertext groups at stream start")
    ciphertext = match.group().decode("ascii")
    letters = ciphertext.replace(" ", "")
    key = "PRALAYA"
    plaintext = "".join(
        chr((ord(c)-ord(key[i % len(key)])) % 26 + ord("A"))
        for i, c in enumerate(letters)
    )
    print("Ciphertext:", ciphertext)
    print("Plaintext:", plaintext)
    # These word boundaries are interpreted from the decoded text.
    features = ["AGE", "SLEEP", "SKILL", "STRESS", "FOCUS"]
    if plaintext != "".join(features) + "X":
        raise ValueError("Unexpected plaintext; inspect before formatting")
    return "MANU{" + "_".join(features) + "}"
 
 
if __name__ == "__main__":
    print(recover(sys.argv[1]))

Usage:

python scripts/orange03_sealed_features.py sealed_plate.png

Acceptance

MANU{AGE_SLEEP_SKILL_STRESS_FOCUS} was accepted, and the SANC-0061–SANC-0090 fragment became available.

Orange SEC-03 marked cleared with the third archive fragment unlocked

The decoded feature manifest unlocks fragment 3, covering SANC-0061–SANC-0090.

Lesson

The solution had two independent layers:

  1. Find where the message is hidden.
  2. Decrypt what was hidden there.

The ciphertext was not readable merely because we had extracted it. Conversely, knowing the narrative key would not help until we recovered the correct message.

The decoded feature names were the answer to this puzzle. We did not treat them as a substitute for later, unobserved machine-learning task instructions.

Orange SEC-04: identify the modified CSV by hashing its original bytes

In-game title: Wing D Audit Export / Hash Mismatch Registry
Category: file integrity / SHA-256 comparison
Accepted flag: MANU{ration_audit.csv_7dfdbe62}.

The problem

An audit export had been copied from the archive after the breach. The Council's exporter had recorded SHA-256 fingerprints, but someone had changed cells in one file without changing its row count or size.

The provided wing_d_audit_export.zip contained:

  • gate_log.csv
  • intake_ledger.csv
  • ration_audit.csv
  • shelter_roster.csv
  • supply_flow.csv
  • manifest.txt

The flag contract requested the exact filename and the first eight hexadecimal characters of that file's current SHA-256:

MANU{filename_first8}

The current hash was the one we computed from the supplied file, not the older expected hash in the manifest.

Step 1: preserve the evidence bytes

The event warned against opening a CSV in Excel or Sheets and saving it. A resave might change line endings, number formatting, quoting, encoding, or other bytes without changing the values a reader notices.

We read the members directly from the ZIP with Python's zipfile module. We did not parse and rewrite the CSVs, and extracting them to disk was not necessary.

Step 2: compare expected and current hashes

FileExpected SHA-256Current SHA-256Result
gate_log.csv4e0fce2ab1ac419a354b6dadf4cc3140d4a88daab91ca48243fdba056788cb08Same as expectedMatch
intake_ledger.csv3a36555b550bbf3da16499412d47a15699fade729be3d3f378b38e69eb1d3400Same as expectedMatch
ration_audit.csv29ede9a058f9dfd67f829d71ddbcb860c58e0e2c755d98b7366ad2433cd8b9137dfdbe62a83bc960a479317d8eb84efd6c5df451a2bddd225da2cfb01aec8da4Mismatch
shelter_roster.csv35a81c9fe54136454210e9891e4d5021c80f8697c8afae4f6e7deacbfc37f9a0Same as expectedMatch
supply_flow.csv5afc4fd03c1430d16444daa5f7e1416f2d227f676459d8741423985ed3fb9c5aSame as expectedMatch

Exactly one file mismatched:

ration_audit.csv

Reproduction

# script: orange04_hash_mismatch.py
import hashlib
import sys
from zipfile import ZipFile
 
 
def inspect(path):
    flags = []
    with ZipFile(path) as archive:
        lines = archive.read("manifest.txt").decode("utf-8").splitlines()
        for line in lines:
            line = line.strip()
            if not line or line.startswith("#"):
                continue
            expected, filename = line.split(maxsplit=1)
            current = hashlib.sha256(archive.read(filename)).hexdigest()
            verdict = "MATCH" if current == expected.lower() else "MISMATCH"
            print(filename, verdict, current)
            if verdict == "MISMATCH":
                flags.append(f"MANU{{{filename}_{current[:8]}}}")
    return flags
 
 
if __name__ == "__main__":
    for flag in inspect(sys.argv[1]):
        print(flag)

Usage:

python scripts/orange04_hash_mismatch.py wing_d_audit_export.zip

Step 3: build the requested answer

Current hash prefix:

7dfdbe62

Exact filename:

ration_audit.csv

Submission:

MANU{ration_audit.csv_7dfdbe62}

Acceptance and Orange convergence

The site accepted the final flag and displayed ARCHIVE CONVERGENCE COMPLETE. The hub subsequently confirmed Orange cleared, 1,300 total points, 3/4 dataset fragments, and Red unlocked.

Orange zone displays Archive Convergence Complete

All four Orange sectors cleared. This image captures the convergence panel before its final download control was activated.

The screenshot captures the convergence panel before its final download control was activated. Later UI marked that control DOWNLOADED and armed the redirect. We did not find a local fragment_4.csv afterward, so that particular download is not counted as a successfully retained artifact.

We did recover the complete forensics_final.csv through the main hub's authorized vault link. That is the retained full forensic dataset.

What the hash comparison proves

It establishes that the current member's bytes differ from the manifest's expected bytes. It does not identify which cells changed or who changed them.

The challenge asked for the mismatching file, so we did not need to invent a content-level diff or reverse a cryptographic hash.

The separate Radio carrier-lock task

This was an accepted investigation step without a new flag string. It explains how the main Radio investigation reached 3/3.

The Failed Logs tab listed:

LogTransmitterFailed handshakesSector
FAIL-LOG-01SANC-00102Forensics
FAIL-LOG-02SANC-00035Radio
FAIL-LOG-03SANC-00124Community

The instruction was to select the distress log with the maximum five failed packets and align the receiver synthesizer.

We selected FAIL-LOG-02, chose the 156.30 MHz emergency repeater preset, and used LOCK CARRIER WAVE & VERIFY ANOMALY.

The site confirmed:

  • DISTRESS ANOMALY CARRIER LOCKED AT 156.30 MHz.
  • SANC-0003's handshake pattern confirmed.
  • Investigation counter advanced from 2/3 to 3/3.
  • Emergency Broadcast override became available.

This frequency belonged to the carrier-lock subtask. CTF 04's navigation reference still came from SIG-03 at 151.40 MHz. Keeping those two trails separate prevented a misleading frequency match.

Emergency Broadcast: a reconstructed image and an unresolved answer

Status: partially completed. No final-answer acceptance was recorded.

What we completed

After the carrier lock, PROCEED TO EMERGENCY BROADCAST opened a sixteen-fragment image reconstruction puzzle.

Each displayed tile used a crop from the same image with background-size 400% 400%. We inspected the rendered tiles' background-position attributes, then used the puzzle's normal fragment buttons to swap them into their corresponding positions.

For a four-by-four grid, an image crop position identifies its original column and row:

column = round(x_percent / (100 / 3))
row = round(y_percent / (100 / 3))
target_slot = 4 × row + column + 1

For example, a crop at x=100%, y≈33.3333% belongs at row 1, column 3 when counting from zero, which is slot 8 when counting slots from one.

The initial visible tile order, expressed as each tile's target slot, was:

[8, 13, 7, 12, 11, 3, 10, 9, 15, 16, 2, 14, 4, 6, 5, 1]

This method used the rendered crop coordinates. It was not a manual visual jigsaw solve and was not a read of a hidden JavaScript answer constant. That distinction matters when explaining the method: it was a reconstruction from visible crop geometry.

A batch of swaps exceeded the browser tool's timeout. Later, the live UI showed the complete transmission image and the final-answer field, confirming that reconstruction had finished despite the tool interruption.

The final image

Fictional Bluezone communications facility with radio towers, coordinates, and an offline status

The Emergency Broadcast image recovered from the sixteen-tile puzzle. Reconstructing it did not establish an accepted final answer.

The image displayed:

  • BLUEZONE COMMUNICATIONS FACILITY.
  • 34.0522° N, 118.2437° W.
  • REBUILD // RECONNECT // SURVIVE.
  • LAST KNOWN TRANSMISSION: 14:32:17.
  • STATUS: OFFLINE.
  • STAY ALIVE.
  • B1 and B2 building labels.

An external map lookup placed the printed coordinates in Los Angeles. A read-only metadata check found no EXIF answer or readable appended flag in the JPEG.

What did not work

The console gave a generic instruction to study the image and determine the final answer. It did not display a specific question or answer format.

These submissions were rejected:

  1. Los Angeles.
  2. BLUEZONE{LOS_ANGELES}.
  3. BLUEZONE COMMUNICATIONS FACILITY.

They are failed hypotheses, not alternate accepted flags.

I later considered whether the answer might relate to Kapu. We had already verified Kapu as the destination for the separate Signal Monitor CTF. No recorded acceptance established it as this image console's answer.

The local Radio countdown later displayed EXPIRED. The hub still confirmed Blue cleared and provided radio_final.csv after CTF 04. We do not have evidence that the final Emergency Broadcast answer was ever solved.

Lesson

A correct geographical observation can still fail to answer an under-specified prompt. Do not turn a plausible interpretation or a successful jigsaw reconstruction into a claim of final challenge acceptance.

Red / Research: where the preserved technical record stops

Status: investigation started; no accepted Red flag in this record.

The hub unlocked Red after Orange cleared. We launched it through the map, preserving the intended authorization flow.

The 3D world showed five fragments in sequence. The starting location was near Central Atrium, associated with locked Fragment 04. We did not access that locked challenge.

Instead, we drove to GHOST SIGNAL, the first available node, exited the vehicle, entered the relay chamber, walked into range of its console, and used E to interact.

The modal offered:

  • A flag submission field.
  • OPEN IN-SITE CTF WORKSTATION.
  • DOWNLOAD PARENT DATASET.

The workstation opened the event-provided Sanctuary Network Records Authority interface:

Original challenge resource

The offered dataset URL was:

Original challenge resource

That dataset had not been downloaded at the end of these notes.

Inside the archive, the visible tools were CASE INDEX, FORENSICS, DATA MATRIX, RELATIONS, RECOVERY, SYSTEM, and TERMINAL.

The public register published six of 120 addresses. The normal lookup field explicitly supported S001 through S120. An advisory recovery directive referred to fully verified identities, records never falsified to protect someone, and correct signatures, while warning that the terminal was wrong about one record.

We had not yet reconciled that directive with the underlying data. No exploit payload, bulk enumeration, matrix scan, recovery, or attestation was performed.

The last state was DATA MATRIX selected, with SCAN INDEX available and no snapshot loaded. Red remained 0/5.

The technical record ends here. It does not document a Red solution, a research_final.csv recovery, a Purple completion, or an ML submission. My third-place finish is the overall result; those missing technical stages are not reconstructed from the earlier checkpoint.

Dataset recovery and the limits of the recorded work

The retained full datasets were:

DatasetVerified recovery checkpointSHA-256
community_final.csvCommunity accepted; Yellow cleared6718dc0345345bd0b59a4e3f3d884f07325e0a306c9484db20bab9bbccc00897
radio_final.csvCTF 04 accepted; Blue cleared6b0a48a15dd27680ee7a0b6699e069423db4c84b7d9a8a652d5d97f5328916d2
forensics_final.csvFour Orange sectors accepted; Orange clearede80c98b987631144570f86167ddb5b375c7d7afa8c23f23e882eae040960b886

The community profile retained 120 unique Sanctuary_ID values across 120 rows and 20 columns. No duplicate IDs or blank/whitespace-only cells were found. Text markers such as Not Logged still represented missing or unavailable information.

Registry recognition counts were recognized 86, partial 22, and unrecognized 12. Twenty-three rows carried the note Resident responded to citywide emergency alert.

These were descriptive checks, not survival labels. Status_Index and Registry_Recognition_Flag were not established as the ML target.

No training labels, evaluation metric, join contract, or prediction-file specification had been recovered in this record. train.csv and sample_submission.csv were still locked behind Purple at the last relevant checkpoint. The Radio and Forensics datasets had not been profiled or joined.

The documented achievement at this checkpoint was data recovery through CTF progression. A trained survival model and its final submission are outside this preserved record.

Evidence fingerprints and reproduction boundaries

The offline checks use the original challenge inputs identified below. Raw artifacts are not bundled with this writeup; provide files you retained from the event when running the scripts.

InputSHA-256
va-07.65b9c55b.wave0275a537c1a700f23eca9f71d6ee52ecb7958d2e562103035807d51a1667a08
intercept-03.55b4f5c0.wavd446961bec85750a992ed5842bf53d0d8a71a9739a6a39165a012023c64bfa35
sealing_certificate_original.pdfeec5c975d27a2bf948cbbb9cf63dfc250f1f673cc19ddf6ad9ea5ea5e3033819
sealing_certificate_edited.pdf31cbd68b01093e2a9d4f4ec15cc030e48aed4355ab71cc2bb97fc6cf9f2c4b52
sealed_plate.png245c799c3b1ca65fe1b8d77a96a915037966497d4c5375fad9e874b4c8a0a974
wing_d_audit_export.zip3ea037b172d374753576b078cef644c56fb6ce00533236ff050eebb4666d17c6

Git artifact snapshot: HEAD 42c38ac15974e004f136f01837de1234a2e041ba, 1,000 commits, one distinct tree.

The source records for this retrospective are the historical solve notes, the session's saved progress notes, the original analysis scripts, retained JSON measurement reports, local challenge files, observed acceptance states, and the included screenshots.

The notes refer to earlier acceptance screenshots for Sanctuary, Community, and the first Radio tasks. Those images are not included in the retained publication assets; the six illustrations here are the ones actually supplied.

Download the reproduction scripts

Download all seven Python reproduction scripts

The download contains the inspected scripts and a short requirements note. Original challenge files and datasets are not included. The source pack reports historical verification against retained artifacts; this post preserves those results without claiming a fresh replay of unavailable inputs.

Reproduction commands

The original solve used Python's standard library plus NumPy, Pillow, and pypdf for the relevant tasks. Git is also needed for SEC-01. The scripts are supplied as documentation companions and do not submit flags or contact live event interfaces.

python scripts/radio03_decode_morse.py va-07.65b9c55b.wav
python scripts/radio04_decode_dtmf.py intercept-03.55b4f5c0.wav
python scripts/orange01_git_lsb.py Orange_zone_archieve
python scripts/orange02_pdf_editor.py sealing_certificate_original.pdf sealing_certificate_edited.pdf
python scripts/orange03_sealed_features.py sealed_plate.png
python scripts/orange04_hash_mismatch.py wing_d_audit_export.zip

The Radio CTF 02 helper requires the original Base64 packet as a separate text file; that ciphertext is not in the retained notes.

Original event references

These links identify the source material used during the competition. They do not assert that a site remains accessible or that an expired session can be reused.

What I took away from a third-place finish

The most useful habit in this run was to write down the requested answer before chasing interesting clues. Community needed a dataset, a cycle, a time, and a source node. The PDF needed a first name and a UTC minute. The hash puzzle needed the current digest, not the expected one. Solving the wrong question carefully still produces the wrong flag.

A second habit was to look for the layer that actually varied. In Orange SEC-01, file contents were constant but commit timestamps were not. In SEC-03, visible artwork and a ROT13 decoy distracted from the RGB least significant bits. In Radio, a decoded sentence sometimes identified the next archive rather than the final answer. The transformation was only one part of the investigation; deciding what its output meant was another.

Preserving bytes mattered just as much as choosing tools. Re-saving a PDF could replace its metadata. Recompressing a PNG could destroy hidden bits. Rewriting a CSV could invalidate its hash. Working from unchanged originals kept the later comparisons meaningful.

Finally, I learned to keep observed, decoded, and accepted results separate. We reconstructed the Emergency Broadcast image, but its final answer remained unverified in the notes. We recovered three full datasets, but the record does not describe a trained model. Third place is the result I’m proud of; the value of the write-up is making the documented reasoning useful enough for someone else to follow.