81 lines
4.2 KiB
Markdown
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/>
|