TJCTF 2018: Moar Turtles
|TJCTF 2018||Moar Turtles||Forensics||80||12 solves|
Hint: I’m a pro fortnite console player so I’ll let you in on a little secret. My controller’s deadzone is 0.2.
We had a PCAP with USB packets comming from XBOX 360 controller. We had to search for a description of leftoverdata, then re-draw with given data.
The hardest point was to think about velocity and find documentation about XBOX 360 controller mapping.
First thing to do with the pcapng file was to extract the USB data and the time associated to each packet. I used the following command to extract data:
tshark -r flag.pcapng -T fields -e frame.time_relative -e usb.capdata > flag.raw head -n 3 flag.raw 0.000000000 00:14:00:00:00:00:47:07:33:10:85:fe:63:07:00:00:00:00:00:00 0.015999000 00:14:00:00:00:00:fe:05:c7:11:85:fe:fc:06:00:00:00:00:00:00 0.028011000 00:14:00:00:00:00:b5:04:92:12:85:fe:63:07:00:00:00:00:00:00
File: flag.raw - md5: a6a74f0d3d924e62c02d89b1795ab8eb
To identify the diffents bytes, i decided first to get the number of possible value for each bytes:
f = open("flag.raw").read().split("\n") # Array of time - data f.pop() # remove empty line times =  bytesl = [ for x in range(20)] # List of 20 lists for l in f: # for each packet p1,p2 = l.split("\t") times.append(float(p1)) # add time of pack in an array sub = p2.split(":") for i in range(20): # add each bytes in a specific array bytesl[i].append(sub[i]) for i,l in enumerate(bytesl): print(str(i)+" : "+str(len(set(l)))) # Print nuber of values for each bytes position
0 : 1 1 : 1 2 : 1 3 : 2 4 : 1 5 : 11 6 : 256 7 : 254 8 : 208 9 : 252 10 : 3 11 : 1 12 : 3 13 : 2 14 : 1 15 : 1 16 : 1 17 : 1 18 : 1 19 : 1
Here we can see that bytes at index 6 to 9 could code the joystic moves.
To confirm our supposition, we’ve been looking for documentation:
We can see that x is coded with a signed int on bytes at index 6 and 7. Y is coded with index 8 and 9.
Since we got an image, and the challenge is called Moar Turtles, we decided to redraw a picture from the givent packets.
Parsing packets: - x and y data are not position but movement. It’s important to set a point and change the position of this point progressivly - Draw only when A is pressed - Include velocity (time parameter)
First try we didn’t notice the velocity parameters. We got lots of junk images.
Here is the final script - md5: ba19714088c919a8b1fcca4af9a165a5
# -*- coding:utf-8 -*- from Tkinter import * import struct # tshark -r flag.pcapng -T fields -e frame.time_relative -e usb.capdata > flag.raw f = open("flag.raw").read().split("\n") # Array of time - data f.pop() # remove empty line times =  bytesl = [ for x in range(20)] for l in f: # for each packet p1,p2 = l.split("\t") times.append(float(p1)) # add time of pack in an array sub = p2.split(":") for i in range(20): # add each bytes in a specific array bytesl[i].append(sub[i]) fen = Tk() # Initializing Tkinter Canvas 1200*800 screenWidth = 1200 screeHeight = 800 screen=Canvas(fen, bg="#d0d0d0", height=screeHeight, width=screenWidth) screen.pack(expand=YES, fill=BOTH) cursorX = screenWidth/2 # Set cursor at the middle of the screen cursorY = screeHeight/2 # Set cursor at the middle of the screen for i in range(len(bytesl)-1): # For each packet diff = times[i+1]-times[i] # Get time difference between current and next packet v1 = bytesl[i] # Get bytes of x v2 = bytesl[i] # Get bytes of x v3 = bytesl[i] # Get bytes of y v4 = bytesl[i] # Get bytes of y # Conversion # signed 16-bit, little-endian, north/east positive # x and y in [-32768;32768] ==> [-((256**2)/2);(256**2)/2] # then divide by 32768 to resize interval in [-1;1] x = float(struct.unpack('<h',chr(int(v2,16))+chr(int(v1,16))))/32768.0 y = float(struct.unpack('<h',chr(int(v4,16))+chr(int(v3,16))))/32768.0 deadzone = 0.2 velocityWeight = 300 for t in range(int(velocityWeight*diff)): # Make multiple movement due to velocity if abs(x) >= deadzone: # Check if we're not in deadzone cursorX += x if abs(y) >= deadzone: # Check if we're not in deadzone cursorY -= y # - due to inversion of y (first flag, the image had mirror effect) if bytesl[i] != "00": # If "A" is pressed (see documentation) screen.create_rectangle(cursorX-1,cursorY-1,cursorX+1,cursorY+1,fill="black",outline="black") # Write Current Pixel fen.mainloop()