10
2
Fork 0
has-writeup/ground-segment/talk-to-me-goose/README.md

4.6 KiB
Raw Permalink Blame History

Talk to me, Goose

Category: Ground Segment Points (final): 94 points Solves: 42

LaunchDotCom has a new satellite, the Carnac 2.0. What can you do with it from its design doc?

Given files: cmd_telemetry_defs.zip, LaunchDotCom_Carnac_2.zip

Write-up

by erin (barzamin).

Inside LaunchDotCom_Carnac_2.zip is a documentation PDF describing the "satellite" we're connecting to. One of the interesting things it notes is that "LaunchDotCom recommends Ball Aerospaces COSMOS suite of software for command and telemetry processing with the Carnac 2.0."; we already set this up for the That's not on my calendar challenge (written up by haskal in this report).

We're given an XTCE file inside cmd_telemetry_defs.zip, cmd_telemetry_defs.xtce, which describes the command/telemetry protocol to the satellite. COSMOS can load an XTCE definition into a COSMOS configuration, so we just generated a new COSMOS configuration tree and imported cmd_telemetry_defs.xtce. Out of the box, this won't identify packets properly for some reason.

To fix this, we created a config $COSMOS/config/targets/CHALLENGE1/target.txt containing TLM_UNIQUE_ID_MODE to make COSMOS fall back to a non-hash-based packet ID mode for the imported XTCE CHALLENGE target to work.

We also had to write an interface config for COSMOS so it could connect to the TCP-tunneled-CCSDS telemetry port the challenge gives us after a ticket; ours was of the form

TITLE 'COSMOS Command and Telemetry Server'
# 10 nil: read, write timeouts
# length: protocol frame decoder
#   32: bit offset in packet to length field
#   16: size of length bitfield
#   7:  length value offset (true # bytes read is length + this)
#   1:  1 byte per count in length field
#   BIG_ENDIAN: endianness *of length field*
INTERFACE LOCAL_CFS_INT tcpip_client_interface.rb {ip} {port} {port} 10 nil LENGTH 32 16 7 1 BIG_ENDIAN
  TARGET CHALLENGE1
  TARGET SYSTEM

and was generated by a script which connected to the challenge, passed the token, and templated/wrote out this interface config file to $COSMOS_CONFIG_DIR/config/tools/cmd_tlm_server/cmd_tlm_server.txt. We ran COSMOS in the Docker container detailed in That's not on my calendar (I'm so sorry for the lack of themes in the docker container; everything looks like Win95).

Connect with COSMOS [hacker voice im in]:

COSMOS CMD/TLM server connected

Almost the packets we're getting are EPS PACKETs indicating undervoltage:

COSMOS showing that the goose is hungry

According to the manual PDF, the EPS shuts off "non-essential subsystems" in this state (which probably includes the subsystem that should be sending us flag packets). Immediately after starting a connection, though, we can send a LOW_PWR_THRESH command with a LW_PWR_THRES of 5V to put the low-power threshold below the battery voltage so the EPS thinks it's no longer running out of power:

COSMOS displaying command sender for LOW_PWR_THRESH

And then all we have to do is send an ENABLEPAYLOAD command:

COSMOS displaying command sender for ENABLEPAYLOAD`

The goose is now happy and FLAG_PWR is on!

COSMOS showing a happy goose

The flag will come back whenever the flag task's scheduler fires, in a FLAG_PACKET:

COSMOS showing we have a FLAG_PACKET

Instead of decoding the packet into fields in COSMOS (that won't show us an ASCII string, just FLAG1, FLAG2, etc integer fields in a list), I copy-pasted the flag packet from COSMOS's hexdump:

COSMOS displaying FLAG_PACKET

And threw together a quick script to decode by inspection of the XTCE file's defintion of the flag layout (basically identical to Can you hear me now?):

from bitstring import Bits, BitArray, ConstBitStream

b = ConstBitStream('THE_HEX_HERE')
packetlocs = list(b.findall('0x0066'))
print(f"found packets:  {packetlocs}")

for loc in packetlocs:
	b.pos = loc
	ver = b.read(3).uint
	ty = b.read(1).bin
	sec_hd = b.read(1).bin
	apid = b.read(11).uint
	gp_flags = b.read(2).bin
	ssc = b.read(14).uint
	plength = b.read(16).uint

	print(ver, ty, sec_hd, hex(apid), gp_flags, ssc, f'len={plength} ({hex(plength)})')

	flag = []
	for i in range(120):
		flag.append(chr(b.read(7).uint))
	print(''.join(flag))

Flag achieved; another can-you-use-COSMOS challenge down.

Resources