| name | satellite-ctf |
| description | Lab/CTF: satellite and space-system challenges; CCSDS Space Packets, TC/TM/AOS/USLP Space Data Link transfer frames, CLTU/BCH/Reed-Solomon coding, COP-1/FARM sequence control, ECSS PUS services, SDLS/SDLS-EP link-layer crypto and CryptoLib CVEs, CubeSat Space Protocol (CSP), TLE/SGP4 orbits, GPS L1 GNSS spoofing with gps-sdr-sim/HackRF, and ground-segment targets (Yamcs, OpenC3 COSMOS, NASA cFS, NOS3, Kubos) including known 2025–2026 RCE/path-traversal/DoS CVEs. Use when a task mentions spacecraft ID, APID, virtual channel, telecommand/telemetry, transfer frame, ground station, modem, ASM 1ACFFC1D, SPI/OTAR/ARSN, or a downlink/uplink byte stream to build or decode. |
| license | MIT |
| compatibility | AgentSkills-compatible agents; local artifacts; authorized isolated lab environments. |
| metadata | {"author":"AeonDave","version":"1.0","category":"ctf-solving"} |
Satellite CTF
Solve satellite and space-ground-link challenges by pinning the exact CCSDS/ECSS layer in play, then building or decoding one spec-compliant unit at a time and using the target's replies as the oracle.
When this skill applies
- Wording: spacecraft/satellite, ground station, uplink/downlink, telecommand (TC), telemetry (TM), transfer frame, space packet, modem, mission control, onboard software, bus/payload.
- Identifiers: APID, VCID (virtual channel), SCID (spacecraft ID), MAP ID, packet sequence count, frame sequence number N(S), service/subservice
TC[x,y]/TM[x,y].
- Protocol cues: CCSDS, ECSS, PUS, CLTU, BCH, Reed-Solomon, Attached Sync Marker
0x1ACFFC1D, pseudo-randomizer, COP-1, FARM/FOP, CLCW, AD/BD/BC frames, CubeSat Space Protocol (CSP), AX.25, KISS, AOS, USLP.
- Security cues (SDLS): SPI, IV, ARSN, MAC/tag, OTAR, Security Association (SA), Key Management Service (KMS), Extended Procedures (SDLS-EP), CryptoLib, GCM/CMAC,
clear-mode VC.
- Ground-system cues: Yamcs, OpenC3 COSMOS, NASA cFS / cFE, NOS3, Kubos, Mission Database (MDB), JSON-RPC command API.
- Artifacts: a raw TCP "modem" service, an IQ/WAV/SDR recording, a hex frame dump, a PCAP of a link, a skeleton
client.py with frame-builder stubs, a TLE set, a ground-system container image, or an RSA/AES key with an SPI number.
Operating model
- Identify the layer stack top-down and bottom-up: physical/coding (CLTU, ASM, RS, randomizer) → data link (TC/TM/AOS transfer frame) → network (space packet, CSP) → application (PUS service, custom command grammar). Most CTF services drop the RF/coding layers and hand you a raw framed byte stream over TCP.
- Read the brief as a spec sheet. SCID, APID, VCID, and the exact payload string (e.g.
HEALTHCHECK, <counter>:BEGIN) are usually stated verbatim — use them exactly, not the example values in any skeleton code.
- Build the smallest valid unit first and send it. Probe for a banner: some services greet (
SPACECRAFT LINK ESTABLISHED), others expect the frame first and only then reply — send-then-recv, do not block on a banner.
- Treat every server reply as an oracle. Layered validators emit precise errors (
Expected TC frame with VCFC 1 but got 0, Expected SpacePacket with sequence count 1, invalid payload or sequence state). Each names the next field to fix; walk the error chain instead of guessing.
- When one field is genuinely ambiguous, brute the smallest matrix (counter × frame-seq × packet-seq × type bit), reconnecting/re-syncing per attempt, not a blind large space.
- Prove the result with the flag from the reply. Extract with a regex, verify format, then submit.
Protocol stack (fast map)
- Space Packet (CCSDS 133.0-B): 6-byte primary header — version(3)
000, type(1) 1=TC/0=TM, sec-hdr flag(1), APID(11) | seq-flags(2) 11=unsegmented + seq-count(14) | data-length(16) = payload_len − 1. Payload follows. APID 2047 (0x7FF) = Idle Packet — dropped silently; 2045–2046 reserved (CFDP, ISO 8473).
- TC transfer frame (CCSDS 232.0-B): 5-byte header — TFVN(2) + bypass(1) + ctrl(1) + spare(2) + SCID(10) | VCID(6) + frame-length(10)=total−1 | frame-seq N(S)(8). Optional segment header, then data, then optional 2-byte FECF = CRC-16-CCITT (poly 0x1021, init 0xFFFF). Frame type from bypass/ctrl:
00=AD (sequence-controlled, FARM checks N(S)), 10=BD (expedited), 11=BC (control: Unlock / Set V(R)).
- TM transfer frame (CCSDS 132.0-B): 6-byte header (SCID/VCID/MC+VC frame counts/data-field-status), data field, optional OCF = CLCW (4 bytes, carries N(R)), optional 2-byte FECF.
- USLP (CCSDS 732.1-B): variable-length modern replacement for TC/TM/AOS; TFVN=
1100; 16-bit SCID; SDLS applies the same way.
- Coding layer (only when RF is in scope): TC uplink wraps frames in a CLTU (start
0xEB90, 8-byte BCH codeblocks, tail C5C5C5C5C5C5C579, optional randomizer). TM downlink prefixes each frame/codeblock with ASM 0x1ACFFC1D (or inverted 0xE5300FE2 on NRZ-M/S bit-sense flip), optional Reed-Solomon (255,223) and pseudo-randomizer.
- Link-layer security (CCSDS 355.0-B SDLS + 355.1-B SDLS-EP): SDLS header (SPI, IV, ARSN) + encrypted data field + trailer (MAC) sit inside the transfer frame data field. Baseline crypto (CCSDS 352.0-B-2) = AES-256 GCM (96-bit IV, 128-bit MAC) or CMAC-only. SDLS deliberately does not protect BC directives or CLCW.
clear-mode VC = header present, no crypto.
- Application: ECSS PUS service/subservice (
TC[17,1] ping → TM[17,2]), or a mission-custom ASCII/binary command grammar.
- CubeSat alt-stack: CSP (32-bit v1 / 48-bit v2 header, ports 0–7 = ping/buffer), often over CAN/KISS/AX.25 on GOMspace hardware.
See references/ccsds-frame-construction.md for exact bit layouts and a working Python builder; references/cop1-and-pus.md for FARM/FOP sequence control and the PUS service catalog; references/sdls-and-ground-cves.md for SDLS/SDLS-EP grammar plus CryptoLib/cFS/OpenC3/Yamcs CVEs.
Technique integration
Load these as decision engines when their domain appears:
technique-ctf for the general challenge-solving loop, oracle-driven iteration, harness building, and parallelizing independent variants.
network-technique and pcap-style analysis for link captures, service exposure, and stream reconstruction.
reversing-technique for onboard-software binaries, custom modem servers, cFS/Kubos apps, and firmware.
wireless-technique for IQ/SDR captures, demodulation, and physical-layer recovery before framing.
crypto-technique when frames are authenticated/encrypted (SDLS, HMAC, XTEA on CSP) or a checksum must be forged.
python-patterns for frame builders, parsers, and replay harnesses; pwntools for the socket loop.
Tool routing
- Frame build/parse (Python):
spacepackets (CCSDS Space Packet + ECSS PUS TC/TM, CRC-CCITT), ccsdspy (fixed/variable TM packet parsing), construct/struct for custom layouts, crcmod (crc-ccitt-false) for PUS/TC CRC, pwntools for the remote loop.
- SDR / demod: GNU Radio +
gr-satellites (AX.25, GOMspace U482C/AX100, CCSDS, AO-40/FUNcube), SatNOGS, inspectrum, Universal Radio Hacker, rtl_433, noaa-apt/SSTV decoders for weather-image tasks.
- Orbits:
skyfield, sgp4, pyorbital, gpredict for TLE propagation, pass prediction, azimuth/elevation and ECEF/geodetic conversion (Hack-A-Sat "AAAA"/ground-segment tasks).
- Ground systems: Yamcs, OpenC3 COSMOS, NASA cFS, NOS3, Kubos — for command/telemetry DB inspection, replay, and finding weak auth / plugin RCE in the ground segment itself.
- Inspect: Wireshark CCSDS/space dissectors,
xxd/CyberChef for hand-decoding a hex frame, libcsp utils for CSP.
Safety and scope gates
- CTF targets are isolated lab services — interact freely, but never transmit on real RF or licensed/amateur bands, and never command a real spacecraft.
- Prefer offline decode of a supplied capture over live interaction when the artifact already contains the answer.
- Keep a field ledger: layer hypothesis → evidence (server error / decoded bytes) → fix → next field. The layered errors are the map; do not brute blindly.
- State which fields are inferred vs. spec-stated; a wrong SCID/APID/VCID is silently dropped by a real validator, so confirm them against the brief first.
Quick pivots
- No banner ≠ dead: if
recv() times out on connect, the service is waiting for the frame — send first, then read.
- Use stated params, not skeleton defaults: a provided
client.py often ships apid=42, vcid=3 placeholders; the brief's real APID/VCID/SCID override them.
- APID looks right but drops silently? You may have rolled to a reserved value — 2045 (CFDP), 2046 (ISO 8473), or 2047 (Idle Packet,
0x7FF) — double-check your mask.
- AD frame won't advance: FARM requires
N(S) == V(R); V(R) starts at 0 and increments per accepted frame. TC N(S), Space Packet sequence count, and an application payload counter are independent. An ACK may report the completed operation's counter while the next command expects the following value; test returned and returned+1 without changing the valid link fields.
- Stuck FARM / lockout: recover with a BC frame —
Set V(R) = 0x82 0x00 <VR>, Unlock = 0x00 (bypass=1, ctrl=1).
- CRC rejects the frame: TC/PUS use CRC-16-CCITT (poly 0x1021, init 0xFFFF, no final XOR); confirm you hash the header+data with the FECF excluded.
- PUS ack silent? Toggle all four ack flags (acceptance/start/progress/completion) in the TC secondary header — each downlink report is an independent oracle for where the command was rejected.
- Counter encoding is literal: payloads like
0x00:BEGIN may be the ASCII string 0x00, not a raw byte — try both encodings when the app rejects a "valid" packet.
- Downlink starts with 1ACFFC1D: strip the 32-bit ASM, de-randomize, RS-decode, then parse the TM frame; flags often sit in the TM data field or a PUS
TM[x,y] report. If the search misses, try the inverted ASM 0xE5300FE2 (NRZ-M/S bit-sense flip) and XOR the stream with 0xFF.
- Hex dump with no service: identify by header — leading
1ACFFC1D = TM/ASM; a 6-byte header with plausible APID = space packet; EB90…C5C5 = CLTU.
- CSP frame: low ports (0–7) are ping/buffer/ident services; check HMAC/XTEA/RDP/CRC flag bits in the header before assuming plaintext.
- Orbit challenge: propagate the given TLE with SGP4 at the stated epoch, convert to the requested frame (ECEF/lat-lon/az-el), and match the expected observation.
SDLS is on — what's still open
- BC directives (Unlock / Set V(R)) and CLCW are not covered by SDLS. Injecting BC frames or flipping CLCW bits (
Retransmit, Lockout) disrupts commanding even against a fully secured link.
- IV reuse on a Security Association = keystream oracle (CryptoLib CVE-2025-46672). Capture multiple frames on the same VC/SA and inspect the Security Header IV — same IV twice = XOR-recover plaintext.
- EP channel confusion (CryptoLib CVE-2025-46675): CryptoLib matches EP PDUs by VCID or APID rather than the spec's reserved SPI 1 / SPI 65535. If a challenge notes this parser, forge an EP directive on the wrong-but-accepted channel → erase SAs → OTAR your own key → own the bird.
clear-mode VC in a mission config = SDLS effectively off on that VC.
- Load
sdls-and-ground-cves.md for full grammar and the OpenC3/cFS/Yamcs CVE catalog.
Ground-segment fast paths
- OpenC3 COSMOS ver 5.0.6–6.10.1: unauthenticated RCE on
/openc3-api/api — JSON-RPC cmd with array-form params executes Ruby before authorize(). Default creds: openc3password, scriptrunnerpassword, openc3service.
- NASA cFS Aquila (2019): TC to Memory Management module = RCE (CVE-2025-25373, CVSS 9.8); OSAL path traversal (25371); MM segfault (25372); app-launch DoS (25374). Common lab wrapper: NOS3 (cFS + COSMOS + Yamcs).
- Yamcs: enumerate the Mission Database (MDB) for command/parameter IDs before crafting a TC — the schema is the challenge.
- Kubos over-the-space update: the "auth checksum" is often a trivial CRC / fixed-key XOR; reverse the client instead of brute-forcing.
GNSS spoofing (when a receiver, not a spacecraft, is the target)
- Toolchain:
gps-sdr-sim (offline .bin from RINEX + target lat/lon/time) → hackrf_transfer -f 1575420000 -s 2600000.
- Spoof alone rarely wins vs. a live receiver — jam L1 first to force loss-of-lock, then broadcast the fake so the receiver reacquires on your signal.
- Sample rate must match end-to-end:
gps-sdr-sim default 2.6 MHz vs GNSS-SDR default 4 MHz — one number off = channel loss.
- Multi-band (RTK, dual-freq) receivers cross-check L2/L5 — pure L1 spoof fails.
- Time-spoofing GPS → shift victim clock → TOTP replay window opens.
- Galileo OSNMA blocks bit-level modification spoof; meaconing (record-and-replay) bypasses NMA at signal level.
Hack-A-Sat recurring shapes
- Antenna pointing → satellite ID: PWM from cable IQ → az/el → SGP4 across TLE catalog → intersection across captures = single sat name.
- Ground bugs → space commanding: web/DB vuln on the platform leaks other teams' radio config → inject TC on their VC.
- ADCS control-constant sabotage: no stability check on gain uploads → wheels saturate. Defence: set ADCS
uncontrolled first, then re-enable safe mode.
- RF RE: unknown IQ →
inspectrum (symbol rate) → GNU Radio demod → gr-satellites for known amateurs → hand-deframe otherwise. Failure modes: wrong bit sense (invert), wrong endianness (swap).
- L4 / three-body: analytical solutions don't work — numerical propagation with periodic corrections.
Resources
- references/ccsds-frame-construction.md — exact bit layouts for Space Packet, TC/TM/AOS/USLP transfer frames, CLTU (BCH start/tail/randomizer), TM ASM + Reed-Solomon + pseudo-randomizer, the CRC-16-CCITT routine, reserved APIDs, and a reusable Python build/parse harness. Load when constructing or decoding any frame at the byte level.
- references/cop1-and-pus.md — COP-1 FARM-1/FOP-1 state and sequence logic, separation of TC/Space-Packet/application counters, AD/BD/BC frame semantics, CLCW bit map, Unlock / Set V(R) directives and lockout recovery, the ECSS PUS service/subservice catalog with the TC/TM secondary-header format, and PUS ack-flag oracle usage. Load for sequence-controlled uplink or PUS application grammar.
- references/sdls-and-ground-cves.md — SDLS / SDLS-EP packet layout (SPI, IV, ARSN, MAC), AES-GCM/CMAC baseline, spec-level gaps (BC/CLCW/clear-mode), SDLS-EP directives (OTAR/KMS/SAMS/MCS), CryptoLib CVE-2025-46672 / -46675, NASA cFS Aquila CVE-2025-25371–25374 and CVE-2026-5475/-5476, OpenC3 COSMOS unauth RCE GHSA-w757-4qv9-mghp and the seven-CVE batch, Yamcs / Kubos notes, and kill-chain patterns. Load whenever the link is authenticated/encrypted, when SPI/OTAR/ARSN appear, or when a ground-system server (Yamcs, COSMOS, cFS) is the actual target.
- references/ground-systems-and-rf.md — SDR reception and
gr-satellites decode chains, direct-bit AFSK over complex or PCM I/Q, ZMQ burst boundaries and liveness tests, AX.25/KISS, CubeSat CSP, TLE/SGP4, ground-system attack surfaces, weather-image downlinks, GNSS spoofing, pass-window/sample-grid rules, and Hack-A-Sat patterns. Load for RF/IQ inputs, CubeSat links, orbit math, a ZMQ/SDR modem interface, ground-system targets, or GNSS-receiver challenges.