bytes away
This commit is contained in:
parent
191df36fb8
commit
e4dd59bc50
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
|
@ -0,0 +1,32 @@
|
||||||
|
FROM ubuntu:18.04
|
||||||
|
|
||||||
|
RUN apt-get update -y && apt-get install -y \
|
||||||
|
cmake \
|
||||||
|
freeglut3 \
|
||||||
|
freeglut3-dev \
|
||||||
|
gcc \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
iproute2 \
|
||||||
|
libffi-dev \
|
||||||
|
libgdbm-dev \
|
||||||
|
libgdbm5 \
|
||||||
|
libgstreamer-plugins-base1.0-dev \
|
||||||
|
libgstreamer1.0-dev \
|
||||||
|
libncurses5-dev \
|
||||||
|
libreadline6-dev \
|
||||||
|
libsmokeqt4-dev \
|
||||||
|
libssl-dev \
|
||||||
|
libyaml-dev \
|
||||||
|
net-tools \
|
||||||
|
qt4-default \
|
||||||
|
qt4-dev-tools \
|
||||||
|
ruby2.5 \
|
||||||
|
ruby2.5-dev \
|
||||||
|
vim \
|
||||||
|
zlib1g-dev
|
||||||
|
|
||||||
|
RUN apt-get install -y bundler
|
||||||
|
|
||||||
|
WORKDIR /cosmos
|
||||||
|
CMD /bin/bash
|
|
@ -0,0 +1,79 @@
|
||||||
|
# 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:
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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!).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```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/>
|
|
@ -0,0 +1,44 @@
|
||||||
|
from pwn import *
|
||||||
|
import time
|
||||||
|
|
||||||
|
r = remote('bytes.satellitesabove.me', 5042)
|
||||||
|
r.clean()
|
||||||
|
r.send('THE_TICKET')
|
||||||
|
time.sleep(0.1)
|
||||||
|
r.readuntil('tcp:')
|
||||||
|
[ip, port] = r.readuntil('\n').decode().strip().split(':')
|
||||||
|
port = int(port)
|
||||||
|
|
||||||
|
TEMPL='''
|
||||||
|
TITLE 'cFS Command and Telemetry Server'
|
||||||
|
|
||||||
|
# Can't map same target to two interfaces. Current strategy is to always connect locally
|
||||||
|
# and allow a switch to a PiSat interface. Another option may be to start both interfaces
|
||||||
|
# and then remap the targets.
|
||||||
|
INTERFACE LOCAL_CFS_INT tcpip_client_interface.rb {ip} {port} {port} 10 nil
|
||||||
|
PROTOCOL WRITE ChecksumProtocol
|
||||||
|
|
||||||
|
TARGET SYSTEM
|
||||||
|
|
||||||
|
TARGET CFE_ES
|
||||||
|
TARGET CFE_EVS
|
||||||
|
TARGET CFE_SB
|
||||||
|
TARGET CFE_TBL
|
||||||
|
TARGET CFE_TIME
|
||||||
|
TARGET MM
|
||||||
|
TARGET KIT_CI
|
||||||
|
TARGET KIT_SCH
|
||||||
|
TARGET KIT_TO
|
||||||
|
|
||||||
|
|
||||||
|
INTERFACE COSMOSINT cmd_tlm_server_interface.rb
|
||||||
|
TARGET COSMOS
|
||||||
|
DISABLE_DISCONNECT
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
with open('cosmos/config/tools/cmd_tlm_server/cmd_tlm_server.txt', 'w') as f:
|
||||||
|
f.write(TEMPL.format(ip=ip, port=port))
|
||||||
|
|
||||||
|
r.interactive()
|
|
@ -0,0 +1,6 @@
|
||||||
|
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'")
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 298 KiB |
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
docker run -it -e DISPLAY -e QT_X11_NO_MITSHM=1 --net=host -v $PWD/cosmos:/cosmos cosmos2 bash
|
Loading…
Reference in New Issue