Hitcon Quals 2019 Writeup
Looks like robotics skills are helpful in CTFs
Overview
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
Files
EV3 Player.mp4
ev3_player-a093689215ca733316ae447edb364512d54bd13e.pklg
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:
f.write(combine)
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
Files
EV3 Player.mp4
ev3_arm-17958868466f3801c4926675e13863b838e8e7cc.rbf
Solution
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 in EV3 Arm Commands.
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
else:
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])
else:
penAngle -= float(items[2].split(' ')[1])
else: #Swivel/Turret motion
if int(items[3].split(' ')[1]) > 0:
y += int(items[2].split(' ')[1])
else:
y -= int(items[2].split(' ')[1])
if penAngle != 0: #Plot all points once pen leaves canvas
ax.plot(plotX,plotY)
plotX.clear()
plotY.clear()
else: #Append points
plotX.append(x)
plotY.append(y)
plt.show()
This script would display an image of the “writings” the robot did.
Flag: hitcon{why_not_just_use_the_printer}