Hack-a-sat — Can you hear me now?
--
[ Also available at https://lucasteske.dev/2020/05/hack-a-sat-can-you-hear-me-now/ ]
That challenged asked us to decode a Telemetry data that was being sent over a TCP port. If you open the netcat, the following happen:
Then if you connect to the Telemetry Service using netcat:
In the provided zip file there is a telemetry.xtce
file which is a XML file that tells us how the binary packet is encoded. A quick search over the internet lead me to the Wikipedia: https://en.wikipedia.org/wiki/XML_Telemetric_and_Command_Exchange
It is defined in the CCSDS Green Book (the spec https://public.ccsds.org/Pubs/660x0g1.pdf )
The file has several sections. I will describe a few of them:
- ParameterTypeSet — Describes the type of parameters to be used in the protocol definition
- ParameterSet — Describes parameters to be used in protocol definition
- ContainerSet — Describes the structures inside the protocol
We will get back to them afterwards. I’m bit lazy to check the whole spec since it should be straightforward to read directly the XTCE. I usually find that when it comes to Aerospace Stuff (Sorry NASA and friends) its easier to reverse engineer than read the docs. So I just did a quick look in the documentation and quit (its huge).
By a quick look inside the xtce file we can find how the flag is defined:
Each of the parameters looks like a single character from the flag, but they’re 7 bit encoded. That means if we look at the raw binary, we will not see the flag itself since each ASCII character is 8 bits wide.
In the ContainerSet we can see the possible structs that we received. Let’s take a look in a piece:
That piece specifies a Container called “AbstractTM Packet Header” (I think I will launch a company called Abstract after that) in which there are few entries. These entries are mapped to the binary itself. Notice the parameterRef
which points to a previous defined parameter at ParameterSet section. Let’s take a look:
From there we can infer:
- The field
CCSDS_VERSION
is encoded in 3 bit - The field
CCSDS_TYPE
is encoded in 1 bit - The field
CCSDS_SEC_HD
is encoded in 1 bit - The field
CCSDS_APID
is encoded in 11 bit - The field
CCSDS_GP_FLAGS
is encoded in 2 bit - The field
CCSDS_SSC
is encoded in 14 bit - The field
CCSDS_PLENGTH
is encoded in 2 bytes (16 bit)
If you sum up all, you will get a header that is 6 bytes long. When seeing this two fields came to my attention. The APID
and PLENGTH
. APID is usually refered to APplication IDentification and PLENGTH to Packet LENGTH.
That means that even if there are a lot of packets, we dont need to *really* parse them, just the flag one. We can skip by knowing the APID and Packet Length. So let’s search the Flag packet!
So here I split the image because the packet definition is huge (lots of FLAGXX fields). We can see a new section here: RestrictionCriteria.
That section tells us which is the condition that the parser should met to parse the content as that packet. That says that if a packet has the following Field => Values in the Packet Header:
- CCSDS_VERSION => 0
- CCSDS_TYPE => 0
- CCSDS_SEC_HD => 0
- CCSDS_APID => 102
That means we got our Flag Packet. So let’s assume all packets have a header and make our parser!
I started dumping the netcat to a file so I can process without having to connect every time. That’s simple by just piping:
nc 18.219.199.203 20072 > dump.bin
Then started writing a simple python script. First by
This decodes the header by doing some bit shifting. And if my assumption that every packet has a header and the packet length I could iterate over the file until no bytes are left. Since the file is small, I could load the entire file in the memory. Then running the script gave me:
Got no errors and the data looks fine! We also got the APID 102 which is what the APID for Flag Packet. Then the content should be easy to read.
If we check the Flag Packet definition, besides the header, there is only the FLAGXXX fields there which means the entire content is the flag. Then we can just get the whole content and decode from 7 bit to 8 bit. Do do that, I was really lazy to do the proper bit shifting, so I just created an array with 1’s and 0’s strings, when it reached 8, I packed into a char and added to an array. That would be really slow for big data, but for a 120 byte flag should be good. So thats the code I tried:
Then when running:
BINGO, THERE IS OUR FLAG!
flag{echo22103romeo:GBd3nn6tIl060NgQ1e_mLZx-1ccydJ1LMAtqgZlWURHX-GPLmnLTZ3CfNvIvTi7JkB4hxxM5uuOuCT5SMmfFz2k}
I hope you liked the explanation. I didn’t take a deep dive in XTCE stuff but just the enough to get the flag. The XTCE format looks interesting (pretty much like a protobuf but in XML) and I will take a look eventually. That also has been my first CTF in my life and was really fun to play!
BONUS
We can also decode the EPS data which should give us some satellite info (and a spoiler to the next flag):