CTF Circle - Hack-A-Sat 2020 CTF "Can You Hear Me Now?" Challenge Writeup Written by sen (@sarahemm) ############### ### Summary ### The 'Can You Hear Me Now?' challenge listed a server and port number, and said that a satellite was streaming telemetry on a TCP port. An XTCE telemetry definition file was provided as well, which would presumably describe how to decode the flag out of the stream. ############################ ### Tools/Infrastructure ### Our team has a couple servers we use as a launching point for CTF work, so my work was done on these. No other tooling was needed in the end beyond basic shell tools and Ruby, though I went down a rabbit hole with Cosmos for awhile before changing strategy. ############### ### Preface ### CCSDS is a set of committees that create space communications standards, one of which is CCSDS TM ("TM" being telemetry), which is used in this challenge and other challenges in this CTF. This standard lays out an overall packet format, standard headers, etc. but does not specify details about how data is organized within each packet as this will vary for each use. XTCE (XML Telemetric and Command Exchange) is an XML-based standard format which takes care of this side of things, defining the structure of information that will be carried inside packets for a specific spacecraft or system. ########################### ### Phase 1 - Discovery ### To start off, I looked through the XTCE file provided to see if there was anything obviously related to the flag. One of the containers in this file is called "Flag Packet", with a description of "packet of flag data", so that seemed promising! This contained 120 parameters, and elsewhere in the file these parameters (named FLAG1 to FLAG120) are defined as type 7BitInteger. Next, I connected to the provided IP/port with netcat which gave a message saying that the telemetry service was running on a specific IP and port. I assumed this was the standard CCSDS TM protocol, and started doing some research on what I could use to decode this. ######################## ### Phase 2 - Cosmos ### I did some quick research and it appeared that Cosmos supported reading XTCE format definitions, and having just completed a different challenge ("That's Not On My Calendar") using this software package I figured that might be the fastest way to go about decoding this telemetry. Not being that familiar with Cosmos, I struggled with the tools for awhile. I eventually got the XTCE XML converted to Cosmos config files that it was reading in, but I wasn't able to get the data to actually decode for some reason. I took a step back after half an hour or so of trying to make this work and thought about whether there was a better way to accomplish this. ############################# ### Phase 2.5 - Decoding ### I briefly looked to see if there was a CCSDS TM Ruby gem that seemed easy to use, and while the Cosmos project has a bunch of gems that would likely work for this, I decided they were too complicated to bother with for something that would likely be straightforward to decode with a bit of code. I found the CCSDS TM spec (https://public.ccsds.org/Pubs/132x0b2.pdf), which seemed like it should contain most of what I needed to finish this challenge. My day job in network engineering often involves picking apart packets by eye during troubleshooting, so I figured with the specification and XTCE file I should be able to find the flag. Looking at the CCSDS TM spec, the header of each packet mostly contained data I didn't care about (such as the spacecraft ID), but one piece of info I did need was the length of data following the header. Since the telemetry stream is (per its name) just a constant stream of data, this information is needed so you can tell where one packet ends and the next begins. I threw a quick Ruby tool together which ignored most of the header, just using the length field. It connected to the challenge server, submitted the token, and connected to the telemetry service on the IP and port that was given. It then read in a telemetry header to figure out how much data was in the packet, read that much data, read the checksum, then repeated all of that until there was no more data to get. For now I just had it print all the hex values to the console to see if I could figure out which of the telemetry packets was the one I was looking for. CCSDS TM packets have a field named APID (Application Process ID), which is essentially the type ID of that specific type of packet. The XTCE file indicated an APID of 102 would be the flag packet. ######################### ### Phase 3 - Solving ### Looking over the data that came back, there were several types of small packets, but only one larger packet that repeated now and then. In thinking about it further I realized that was likely the flag given the length, but also that there was actually no need to figure out which was the flag packet since if I just dumped all of them one should say "flag{" at the start! This wouldn't have been as easy if there had been other fields in the flag packet as the alignment might have been off, but since the packet definition shows that the 7-bit values should start right at the beginning of the data I figured this wouldn't be an issue. Still, the data was packed into 7-bit characters so I couldn't just look at it as ASCII without some extra manipulation first. I added some code to take the entire packet, turn it into a long string of binary (literally 1s and 0s in a string), then read that string back 7 "bits" at a time and turn each number into its ASCII character. Not efficient on memory or much else, but efficient on coding time. I'm sure there are lots of better ways to do it, but it got the job done in the CTF timeline. Re-running the tool, several packets of garbage-looking data appeared followed by the flag! ################################## ### LESSONS LEARNED/REINFORCED ### - This CTF reinforced the "step back and see if there's a faster way" thing that I try to keep in mind. After spending a bunch of time on the Cosmos setup I realized that I was way over-complicating things, and after spending time trying to identify specific packet types I realized I was still making it more complicated than it needed to be. The simplest tools sometimes get the quickest results. - Sometimes "parsing by eye" is the fastest way to go, even if you automate it and use the computer's "eye". Picking the data apart to identify specific types of packets is sometimes essential if there's different parsing required for different types, but often if you just decode a stream of data as much as you can then look for things like "flag{" in the stream it ends up being faster. In this case literally doing it by eye was fine, but had there been more data coming in it would have been easy enough to have the tool only show strings if they had the text "flag" contained in them.