10
2
Fork 0
has-writeup/satellite-bus/bytes-away
xenia 553522c799 huge major cleanup for pdf generation 2020-05-26 06:27:26 -04:00
..
COSMOS.png bytes away 2020-05-26 02:01:05 -04:00
COSMOS_MM.png bytes away 2020-05-26 02:01:05 -04:00
COSMOS_enable_telemetry.png bytes away 2020-05-26 02:01:05 -04:00
Dockerfile bytes away 2020-05-26 02:01:05 -04:00
README.md huge major cleanup for pdf generation 2020-05-26 06:27:26 -04:00
connect.py bytes away 2020-05-26 02:01:05 -04:00
dump.rb bytes away: unwrap more 2020-05-26 02:06:19 -04:00
ghidra.png bytes away 2020-05-26 02:01:05 -04:00
launch-docker.sh bytes away 2020-05-26 02:01:05 -04:00

README.md

Bytes Away!

Category: Satellite Bus Points (final): 223 Solves: 11

We have an encrypted telemetry link from one of our satellites but we seem to have lost the encryption key. Thankfully we can still send unencrypted commands using our Cosmos interface (included). I've also included the last version of kit_to.so that was updated to the satellite. Can you help us restore communication with the satellite so we can see what error "flag" is being transmitted?

Write-up

by haskal

Two files are provided for this challenge, one contains the kit_to.so and the other contains a full COSMOS directory tree for accessing the virtual satellite, which can be booted up with the provided netcat endpoint. COSMOS is an open-source command and control framework for satellites using NASA's Core Flight System. The provided COSMOS directory contains everything we need to interact with the virtual satellite, and the kit_to.so is part of the code that runs onboard the actual satellite. Booting up COSMOS is enormously complicated, so Docker can be used to automate the setup. We adapted the Ball Aerospace COSMOS Docker image, and created a script to configure COSMOS to connect to the CTF's satellite instance automatically by writing the configuration file at cosmos/config/tools/cmd_tlm_server/cmd_tlm_server.txt. When COSMOS is successfully connected to the CTF instance it looks like this (no themes were installed in the Docker container so it looks like Windows 95, I'm so sorry,)

COSMOS main window

COSMOS can be used to send commands with the Command Sender, and we can send for example a command for ENABLE_TELEMETRY, which causes the satellite to start sending telemetry. However these are encrypted, so COSMOS cannot understand them.

COSMOS command sender for ENABLE_TELEMETRY

We also discover another present subsystem called MM, which allows for reading and writing arbitrary memory on the satellite (how useful!) as well as interacting with memory by symbols (extremely useful!).

COSMOS command sender with MM PEEK_MEM command

The provided kit_to.so contains the code used by the satellite to transmit telemetry to COSMOS. We used Ghidra to analyze the binary (which helpfully includes symbols and debugging information, and that makes our lives way easier for this problem). We discovered that it uses AES CBC with a key and IV retrieved with external functions get_key and get_iv that are not present in the binary. However, these are stored in known locations in memory, which means it would be possible to read the AES key and IV using the PEEK_MEM command in COSMOS and then decrypt the telemetry packets, but there's an easier way. The code contains a function KIT_TO_SendFlagPkt which (as you might guess) sends the flag via encrypted telemetry, and this also writes the flag as an intermediate value to a known memory location. PIE is enabled for this binary, however since the PEEK_MEM command allows looking up memory by symbol name the address randomization is very trivially bypassed.

KIT_TO_SendFlagPkt in Ghidra showing the global flag location

Inspecting the structure of KitToFlagPkt shows that the flag is located at offset 12 and is (up to) 200 bytes long. We created a Ruby script in the COSMOS Script Runner to execute PEEK_MEM commands for each byte in the flag range, based on the command COSMOS outputs to the console when running the command manually in the GUI. Note that in order for the function KIT_TO_SendFlagPkt to be called at all, we must first run the ENABLE_TELEMETRY command even though we're not going to look at any actual telemetry.

12.upto(212) { |off|
  offset = off
  cmd("MM PEEK_MEM with CCSDS_STREAMID 6280, CCSDS_SEQUENCE 49152, CCSDS_LENGTH 73, "
      + "CCSDS_FUNCCODE 2, CCSDS_CHECKSUM 0, DATA_SIZE 8, MEM_TYPE 1, PAD_16 0, "
      + "ADDR_OFFSET #{offset}, ADDR_SYMBOL_NAME 'KitToFlagPkt'")
}

This directly prints the flag to the console, simply decode the hex to get the flag value.

Resources and other writeups