HTB Baby Frame Writeup
Category: Satellite
Difficulty: Very Easy
Challenge Description
A recently recovered experimental spacecraft broadcasting under spacecraft ID 12 has entered visibility range. Ground telemetry suggests that one onboard diagnostic application remains active on APID 42 over virtual channel 3. Mission operators believe the service is waiting for a single correctly formatted CCSDS space packet containing the user payload
HEALTHCHECK.
We are given a minimal client.py template with two missing functions:
generate_space_packet()generate_tc_frame()
The objective is to implement these functions according to the official CCSDS specifications and successfully communicate with the remote spacecraft simulator.
Initial Analysis
The provided client performs the following operations:
space_packet = generate_space_packet(
apid=42,
packet_count=0,
payload=b"TEST_PAYLOAD"
)frame = generate_tc_frame(
spacecraft_id=12,
virtual_channel_id=3,
tc_packet_count=0,
payload=space_packet
)payload = frame + space_packet
From the challenge description, we know the required values:
FieldValueSpacecraft ID12Virtual Channel3APID42PayloadHEALTHCHECK
The two protocol references included with the challenge immediately point us toward the official CCSDS standards:
- CCSDS Space Packet Protocol
- CCSDS Telecommand (TC) Space Data Link Protocol
This indicates that the challenge is primarily a protocol implementation exercise rather than a traditional exploitation challenge.
Understanding the CCSDS Space Packet
A CCSDS Space Packet begins with a fixed 6-byte Primary Header.
0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Ver|Type|SHF| APID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Sequence Flags| Packet Sequence Count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Packet Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+The header consists of three 16-bit words.
First Header Word
The first word contains:
- Version = 0
- Packet Type = 1 (Telecommand)
- Secondary Header Flag = 0
- APID = 42
This is packed as
Version << 13
PacketType << 12
SecondaryHeader << 11
APIDwhich evaluates to
0x102ASecond Header Word
The second word stores
- Sequence Flags =
11(Unsegmented Packet) - Packet Sequence Count = 0
This becomes
0xC000Packet Length
Unlike most protocols, CCSDS stores
Packet Length = Data Length - 1The payload is
HEALTHCHECKwhich is 11 bytes.
Therefore
Length = 10or
0x000AFinal Space Packet
The packet layout becomes
+----------------------+
| Primary Header (6B) |
+----------------------+
| HEALTHCHECK |
+----------------------+Understanding the Telecommand Frame
The Telecommand Transfer Frame acts as the transport layer for the Space Packet.
The primary header contains
- Spacecraft ID
- Virtual Channel ID
- Frame Length
- Sequence Number
For this challenge:
Spacecraft ID = 12
VCID = 3
Sequence = 0The interesting observation is that the provided template later performs
payload = frame + space_packetinstead of embedding the packet inside generate_tc_frame().
Therefore generate_tc_frame() only returns the 5-byte TC Primary Header, while the client appends the Space Packet afterwards.
The transmitted data therefore looks like
+--------------------+
| TC Header |
+--------------------+
| Space Packet |
+--------------------+This matches the expected packet layout for the challenge service.
Packet Construction
The Space Packet is created by
def generate_space_packet(apid, packet_count, payload):
first = (1 << 12) | apid
second = (3 << 14) | packet_count
length = len(payload) - 1 return struct.pack(">HHH", first, second, length) + payloadThe Telecommand header is created by
def generate_tc_frame(scid, vcid, count, payload):
word1 = scid
frame_len = len(payload) + 5 - 1
word2 = ((vcid & 0x3F) << 10) | frame_len return struct.pack(">HHB", word1, word2, count)Finally, the packet sent to the server is
frame + space_packetwhere the application payload is
b"HEALTHCHECK"Communication Flow
The completed packet follows this structure:
TCP Connection
│
▼
┌──────────────────────────┐
│ TC Transfer Frame Header │
└──────────────────────────┘
│
▼
┌──────────────────────────┐
│ CCSDS Space Packet │
├──────────────────────────┤
│ Primary Header (6 bytes) │
├──────────────────────────┤
│ HEALTHCHECK │
└──────────────────────────┘
│
▼
Diagnostic Service (APID 42)The onboard diagnostic application validates:
- Spacecraft ID = 12
- Virtual Channel = 3
- APID = 42
- Payload =
HEALTHCHECK
If all fields are correctly encoded according to the CCSDS specifications, the spacecraft responds with the challenge flag.
Although classified as a “Very Easy” challenge, it provides an excellent introduction to real-world satellite communication protocols and demonstrates how spacecraft exchange telecommands using CCSDS standards.
