CTF Writeup By 4cad @TheAdditionalPayphones.

For this challenge we are provided with an XML file telemetry.xtce along with a server address and port, and the following challenge description:

LaunchDotCom's ground station is streaming telemetry data from its Carnac 1.0 satellite on a TCP port. Implement a decoder from the XTCE definition.

This telemetry schema file describes the binary layout of the sattelite's telemetry data, as specified by the XTCE spec https://www.omg.org/xtce/index.htm. In hindsight I would have just used Ball Aerospace COSMOS (https://cosmosrb.com/) which came up in a subsequent challenge, but for this intro level one you don't need any tools.

According to telemetry.xtce the flag appears to be encoded as 7 bit integers.

<!-- Parameters used by Payload  -->
<xtce:Parameter name="PAYLOAD_FLAG1" parameterTypeRef="4ByteInteger"/>
<xtce:Parameter name="PAYLOAD_FLAG2" parameterTypeRef="4ByteInteger"/>
<xtce:Parameter name="PAYLOAD_FLAG3" parameterTypeRef="4ByteInteger"/>
<xtce:Parameter name="PAYLOAD_DATA" parameterTypeRef="PayloadBlob"/>
<!-- Parameters used by FLAG Gen  -->
<xtce:Parameter name="FLAG11" parameterTypeRef="7BitInteger"/>
<xtce:Parameter name="FLAG12" parameterTypeRef="7BitInteger"/>
<xtce:Parameter name="FLAG13" parameterTypeRef="7BitInteger"/>
<xtce:Parameter name="FLAG14" parameterTypeRef="7BitInteger"/>

Connecting to the provided port apparently causes the mock telemetry service to be started on another port:

    $ nc hearmenow.satellitesabove.me 5032
    Ticket please:
    ticket{...}
    Telemetry Service running at 18.219.199.203:11335

Dumping the output of netcatting the telemetry service resulted in the following binary blob:

In [11]:
blob
Out[11]:
b'0069cecd000b1c0f20b574dd1529feb7647a0067d3220006034a009f00af8c0067d3230006034300a900af8c0067d3240006033b00b300af3c0069cece000be4135a08780928698be8092a0066c831005fcdb30e7f79f7ecccd9b3760cfce1ddaf2e5751e6f065d71e49cc24c3b536d5291171d9ef1d9e3c74e6b59d2f97a8b43aed9f4dad572dd932a7099c8cb134b3d6db4d887163cecdca16fa7b56f3b136c41836b9e3a506574ecc9c66ad36a55fa00067d3250006033400bc00af3c0069cecf000b996b44eebc9005e7b831bc170067d3260006032c00c500af3c0069ced0000bf391cc84581672023e2a5dc20066c832005fcdb30e7f79f7ecccd9b3760cfce1ddaf2e5751e6f065d71e49cc24c3b536d5291171d9ef1d9e3c74e6b59d2f97a8b43aed9f4dad572dd932a7099c8cb134b3d6db4d887163cecdca16fa7b56f3b136c41836b9e3a506574ecc9c66ad36a55fa00067d3270006032500ce00af3c0069ced1000be20f858b64b1d24d9901c57c0067d3280006031d00d600af3c0069ced2000b26ff25b563b7b9fe4755fb300066c833005fcdb30e7f79f7ecccd9b3760cfce1ddaf2e5751e6f065d71e49cc24c3b536d5291171d9ef1d9e3c74e6b59d2f97a8b43aed9f4dad572dd932a7099c8cb134b3d6db4d887163cecdca16fa7b56f3b136c41836b9e3a506574ecc9c66ad36a55fa0'

Since the schema appears to imply that the flag is encoded as a string of 7 bit integers, it was simple enough to convert it into a binary string and search for the 7-bit encoded prefix of flag{. The telemetry schema seems to suggest that the flag can be 120 characters long so the following python code is able to decode the flag by finding the encoded flag{ value and decoding it along with the 115 characters that follow it:

In [63]:
import re
def bits(x) :
    return bin(x)[2:].zfill(8)

def bits7(x) :
    return bin(ord(x))[2:].zfill(7)

binary = bin(int(blob, 16))
    
prefix = bits7('f') + bits7('l') + bits7('a') + bits7('g') + bits7('{')
flag7bit = re.match('.*('+prefix+'(?:(?:[01]){7}){115})',binary).group(1)

decoded = ''
for i in range(0, len(flag7bit)//7) :
    start = 7*i
    end = 7*i + 7
    decoded += chr(int(flag7bit[start:end], 2))
print(decoded)
flag{golf66703yankee:GMp2ucdN0ICZMZRHEcYwG3ccSM5NKrzEPumOS5U9722SB3HeDi3k6iXCEGNfrBoSm-sXMXAAZscRAJtv28fVMTU}giI`0J