15 Oct 2019

Hitcon Quals 2019 Writeup

Looks like robotics skills are helpful in CTFs


Team Name: HATS SG
Position: 49
Score: 1368

First time actually solving something under HATS SG. Always just went for the meetups and became useless cause I was too noob. Who knew? Suddenly got arrowed to do the robotics challenges because of my background in robotics.

EV3 Player

Points: 207

Challenge Description

Do you hear the robot sing


EV3 Player.mp4

Network Packet Analysis

The first thing I saw was a .pklg file after which I basically flipped as this was nowhere near my area of expertise.

The video shows a EV3 robot playing audio saying congratulations the flag...

The .pklg logs the communication from the computer (MacBook OSX) to a LEGO Mindstorms NXT EV3. After looking at a writeup from previous year’s Hitcon, I found the guides to the LEGO Developer Kits.

LEGO Mindstorms EV3 Firmware Development Kits
LEGO Mindstorms EV3 Communication Development Kits

I analyzed the bytes .pklg with the help of a Wireshark add-on and extracted the following information:

Packet 982 signifies end of download
Packet 991 loads the program and start program
All packets from the MacBook to the EV3 do not contain any instructions to play sound

Packet 1-970: Boot and Download program and other files to EV3
    Packet 500: Begin transfer of file fl.rsf
    Packet 698: Begin transfer of file ag.rsf 

No instructions were sent to the EV3 brick to play any sound. Based on my knowledge of EV3, sound can only be played either by frequencies, musical notes, sound files. Sound files have to be parsed through their sound editor which later converts it to a .rsf (robot sound file). I would guess that the bytes in the .rsf are just frequencies.

Extracting the RSF File

Anyways, looks like our best bet was to extract fl.rsf and ag.rsf. We filtered the packets using the following filter (ev3.sys_cmd=0x092 || ev3.sys_cmd=0x093) && bluetooth.dst == 00:16:53:61:30:c1 which basically restricts the packets to those that are related to the download to the EV3 brick. The bytes of each filtered packet was then extracted manually. A script written by my teammate was used to combine these bytes into a .rsf files while extracting the system commands.

import binascii
combine = ''
for i in range(1,97):
    with open(str(i),'rb') as f:
        content = binascii.hexlify(f.read())
    content = content[12:]
    combine += content

with open('output.rsf','wb') as f:

The .rsf was opened in the LEGO Mindstorms Education EV3 application. When played, we hear a very high-pitched, indistinct sound but it does sound like a audio sped up by 5x. We import the file into Audacity as unsigned 8-bit raw data with no endianness. We then slow down the speed by 5x and increase the volume (as necessary). When playing fl.rsf, we hear congratulations, the flag contains no spaces and all lowercase. This is when we knew we got it. We then did the same process for ag.rsf and the audio file literally read out the flag.

Flag: hitcon{playsoundwithlegomindstormsrobot}

EV3 Arm


EV3 Player.mp4


Finally something I am remotely familiar with. The video shows a robot writing the word hitcon. An .rbf file is a robot block code file used in EV3 to give the robot instructions. Using an online decompiler, we can obtain a line version of LEGO code that we see in the LEGO Mindstorms programming app. We can remove all the extra lines and the beginning characters of lines to make the lines more consistent using a simple text editor since the code isn’t that long. The decompiled and shortened commands can be found here.

Each motor has a port (A,B,C), a speed (Negative and positive numbers) and the distance in which it should move. By the order of movements in the video, I deduced the ports A: Arm swivelling, B: Lowering the pen, C: Base movement. With that, we can write a simple python script to plot out exactly where the marker wrote stuff. We can assume the arm swivelling is linear (along y-axis) because of its relatively large radius of turning and we can take the base movement as translations along the x-axis. We only draw lines when the pen is lowered. The values were then plotted using the library matplotlib in the script below.

import matplotlib.pyplot as plt

with open('commands.txt','r') as f:
    content = f.readlines()

plotX = []
plotY = []

fig, ax = plt.subplots()

penAngle = 35
x = 0
y = 0
for i in content:
    items = i.strip().split(' | ')
    if items[0].startswith("Motor"): #base movement
        if int(items[3].split(' ')[1]) > 0:
            x += float(items[2].split(' ')[1]) * 50
            x -= float(items[2].split(' ')[1]) * 50
    elif items[1] == 'port_motor: B': #Arm controller
        if int(items[3].split(' ')[1]) > 0:
            penAngle += int(items[2].split(' ')[1])
            penAngle -= float(items[2].split(' ')[1])
    else: #Swivel/Turret motion
        if int(items[3].split(' ')[1]) > 0:
            y += int(items[2].split(' ')[1])
            y -= int(items[2].split(' ')[1])

    if penAngle != 0: #Plot all points once pen leaves canvas
    else: #Append points

This script would display an image of the “writings” the robot did.

Flag: hitcon{why_not_just_use_the_printer}