10
2
Fork 0
has-writeup/satellite-bus/bytes-away/README.md

81 lines
4.2 KiB
Markdown

# 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](https://awoo.systems)
Two files are provided for this challenge, one contains the `kit_to.so` and the other contains a
full [COSMOS](https://cosmosrb.com/) 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](https://cfs.gsfc.nasa.gov/). 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.png)
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](COSMOS_enable_telemetry.png)
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](COSMOS_MM.png)
The provided `kit_to.so` contains the code used by the satellite to transmit telemetry to COSMOS.
We used [Ghidra](https://ghidra-sre.org/) 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](ghidra.png)
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.
```ruby
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
* <https://cosmosrb.com/>
* <https://cfs.gsfc.nasa.gov/>
* <https://ghidra-sre.org/>