Lost at Sea — Athena Trace 2026 Writeup
A four-stage chain: read vessel data off a screenshot, derive an AES key from it, pull a ZIP out of the tail of a PNG, and unlock it with the ship's own call sign.
The challenge
An illicit cargo transaction was planned mid-voyage. We have a screenshot from the coordinator’s terminal, a coastal monitoring station’s log from the same night, and three files a port authority was still serving after it pulled the paperwork. Follow what the coordinator left behind and recover the manifest.
Flag format:
trace{...}— the manifest contains the flag exactly as it should be submitted.
Five artifacts:
terminal.png
radio_intercept.txt
trimmu3.png
kaz_berth.png
bqm_approach.png
This is the most technical card on the board — four distinct disciplines chained back to back, where each stage’s output is the next stage’s input. Break one link and nothing downstream works.
Stage 1 — Harvest the vessel data
terminal.png is a MarineTraffic view for a vessel called TRIMMU 3. Everything
that matters later is on this screen:

| Field | Value |
|---|---|
| Vessel | TRIMMU 3 |
| MMSI | 477204900 |
| IMO | 9200469 |
| Call sign | VRXD7 |
| Speed (SOG) | 10.3 kn |
| Route | IQ KAZ → PK BQM |
The route decodes as Khor al Zubair, Iraq → Bin Qasim, Pakistan — which is why
kaz_berth.png and bqm_approach.png exist. Those two turn out to be scene
dressing rather than load-bearing evidence, but they confirm the voyage endpoints
and are worth checking rather than assuming.
Treat this stage as data extraction, not analysis. Copy every field verbatim; you don’t yet know which ones matter.
Stage 2 — Build the key
radio_intercept.txt contains a Base64 block followed by plaintext instructions:
KEY = MMSI_SOG
- MMSI as printed
- SOG in knots, one decimal
- underscore between
AES-256-CBC
- key is SHA-256 of that string
- IV is first sixteen bytes
Substituting from the screenshot:
477204900_10.3
Two details decide whether this works. “MMSI as printed” means no formatting,
no separators — exactly the digit string on screen. “SOG in knots, one
decimal” means 10.3, not 10.30 and not 10. The instructions are pedantic
because the key is a hash: one wrong character and you get noise, with no partial
credit and no feedback about which character was wrong.
Stage 3 — The IV ambiguity
“IV is first sixteen bytes” is genuinely ambiguous — first sixteen bytes of what? Two conventions are common:
iv = key[:16]— the first half of the SHA-256 digest.iv = blob[:16]— the ciphertext is prefixed with the IV, the standard practice for AES-CBC in transit.
The correct reading here is the second: the IV is prepended to the ciphertext.
What makes this worth dwelling on is the failure mode. Trying iv = key[:16]
does not fail cleanly — it produces garbage in the first block and readable
plaintext from block two onward. That’s inherent to CBC: each block is
decrypted with the previous ciphertext block as its XOR input, so a wrong IV
corrupts only the first 16 bytes. The cipher self-heals.
Lesson: in CBC, “mostly readable output” is not confirmation. If the first block is garbage and the rest is clean, your IV is wrong — not your key. A wrong key produces noise throughout; a wrong IV produces exactly one bad block. The damage pattern tells you which parameter to fix.
Working decryption:
import base64, hashlib
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
blob = base64.b64decode(b64_from_intercept)
iv = blob[:16]
ct = blob[16:]
key = hashlib.sha256(b"477204900_10.3").digest()
pt = unpad(AES.new(key, AES.MODE_CBC, iv).decrypt(ct), 16)
print(pt.decode())
Output — an HTTP response:
HTTP/1.1 404 Not Found
Date: Fri, 07 Aug 2026 04:18:22 GMT
Server: nginx/1.24.0
Content-Type: text/html; charset=utf-8
Content-Length: 137
X-Cargo-Manifest: /static/img/trimmu3.png
X-Archive-Note: manifest withdrawn from index 2026-08-07; asset retained
The 404 is the point. The paperwork was pulled from the index, but
X-Archive-Note says the asset was retained — and X-Cargo-Manifest names it:
/static/img/trimmu3.png. That’s the third artifact, and it is not just an
illustration.
This is a realistic pattern worth internalising: withdrawing a document from a listing does not delete the file, and custom response headers routinely leak internal paths long after the content is “removed”.
Stage 4 — The polyglot
trimmu3.png is a valid PNG that renders normally. It also has a ZIP archive
appended after the IEND chunk.

This works because the two formats parse from opposite ends. PNG readers stop at
IEND and ignore trailing bytes; ZIP readers scan backwards from the end of the
file for the central directory. Both see a valid file. Nothing looks wrong.
Detection and extraction:
binwalk trimmu3.png # flags the appended archive
# or, directly:
unzip trimmu3.png # zip finds its own central directory
Inside: manifest.txt, password-protected.
Practical habit: any image handed to you in a forensics-flavoured challenge
gets binwalk and a trailing-bytes check before anything else. Comparing the
IEND offset against the file size takes seconds and catches this whole class of
trick.
Stage 5 — The archive password
Nothing in the prompt states the password, but the framing does: “follow what the coordinator left behind.” Every credential in this chain has come from the terminal screenshot, so the candidate set is the identifiers on that screen:
| Candidate | Value | Reasoning |
|---|---|---|
| MMSI | 477204900 | Already used for the AES key — reuse is plausible but less likely |
| IMO | 9200469 | Permanent hull identifier |
| Vessel name | TRIMMU3 | Obvious guess, spacing ambiguous |
| Call sign | VRXD7 | Radio identity — thematically fits an intercept chain |
The call sign is correct: VRXD7.
In hindsight it’s the thematically consistent answer. The whole chain runs on radio: an intercepted transmission, a coastal monitoring station, a vessel’s radio identity. The call sign is the ship’s identifier on the air, which is the register this challenge operates in.
Note also that the vessel name is a bad candidate precisely because it’s
ambiguous — TRIMMU 3, TRIMMU3, trimmu3 are three different strings. A setter
choosing a password from a screenshot will favour a value with exactly one
rendering.
The manifest
PORT QASIM AUTHORITY -- CARGO MANIFEST (WITHDRAWN COPY)
Vessel : TRIMMU 3 IMO 9200469 MMSI 477204900
Voyage : IQ KAZ -> PK BQM
Transfer : ship-to-ship, position withheld from filed copy
Filed : 2026-08-07
Status : withdrawn from public index
Declared cargo differs from the filed copy. Reconciliation reference:
trace{TR1MMU_3_SUCCE55_051NT}
Flag
trace{TR1MMU_3_SUCCE55_051NT}
Takeaways
- Extract exhaustively before you analyse. At stage 1 there’s no way to know the MMSI and SOG feed a hash while the call sign unlocks an archive four steps later. Copy every field; decide relevance downstream.
- CBC failure patterns are diagnostic. One bad block then clean text means a wrong IV. Noise throughout means a wrong key. Read the damage before changing parameters at random.
- Ambiguous spec language has a default. “IV is first sixteen bytes” resolves to the transit convention — IV prepended to ciphertext — because that’s how AES-CBC is actually shipped in the wild. When a spec is ambiguous, try the real-world convention first.
- Withdrawn ≠ deleted. A 404 with a custom header naming a retained asset is a realistic leak pattern, not just a CTF contrivance.
- Check trailing bytes on every image. PNG-plus-ZIP polyglots are invisible to viewers and to casual inspection, and cost nothing to rule out.
- Guess passwords from the artifact set, thematically. The candidates were all on one screen; the tiebreaker was which identifier fits the challenge’s own register — radio.
Sources
- TRIMMU 3 on VesselFinder — the vessel is real: LPG tanker, IMO 9200469, MMSI 477204900, call sign VRXD7
- TRIMMU 3 on MarineTraffic — the service the terminal screenshot shows
- Khor Al Zubair — IQ KAZ: port city in Basra, Iraq, the voyage origin
- Port Qasim — PK BQM: Port Muhammad Bin Qasim, Karachi, the destination
- Port Qasim Authority — the authority named on the manifest
- PyCryptodome — classic cipher modes —
AES.MODE_CBCusage, including shipping the IV alongside the ciphertext - Block cipher mode of operation — CBC with a wrong IV corrupts only the first plaintext block; the diagnostic the writeup leans on
- PNG specification (W3C) —
IENDis the last chunk of the datastream; readers stop there - PKWARE APPNOTE — .ZIP File Format Specification — the end-of-central-directory record sits at the end of the file, which is why ZIP readers scan backwards
- binwalk — detects the archive appended after
IEND - Challenge: Athena Trace 2026 — “Lost at Sea”
Image credits
All artifacts are challenge-authored files distributed with the Athena Trace 2026 CTF. The vessel identifiers are real — TRIMMU 3 is an existing LPG tanker under IMO 9200469 — and appear to be drawn from public AIS data; the manifest and the scenario built around them are the challenge’s fiction.