Google CTF 2016 - For2
We are given a PCAPNG file with a bunch of USB packets. By scanning through the PCAP, I noticed that there appears to be a large amount of URB_INTERRUPT
packets after some initial configuration and setup. On a hunch, I immediately suspected either a USB keyboard or mouse due to the amount of data and the fact that all incoming packets were created from interrupts (i.e some kinda of slow I/O device driven by a human).
While looking at the packets, I initially assumed this was a keyboard as it would be straight forward to hide a flag in keyboard data. I tried the obvious choice and googled for some Python that already solved this problem and I came across this keyboard PCAP parser. I noticed that the offsets used in the file were not close to the size of the packets I was seeing, so I did some more research on USB HID devices and I came across this great page on USB mice packets.
The packet structure described here matched what I was seeing in the PCAP data. I confirmed this by looked for a USB descriptor packet from the device. I found the right packet at number 84 (below).
No. | Time | Source | Dest | Protocol | Length | Info ----+----------+--------+------+----------+--------+------------------------------ 84 | 6.505211 | 1.3.0 | host | USB | 46 | GET DESCRIPTOR Response DEVICE
The device descriptor decoding showed that this was definitely a mouse.
DEVICE DESCRIPTOR bLength: 18 bDescriptorType: 0x01 (DEVICE) bcdUSB: 0x0200 bDeviceClass: Device (0x00) bDeviceSubClass: 0 bDeviceProtocol: 0 (Use class code info from Interface Descriptors) bMaxPacketSize0: 8 idVendor: Logitech, Inc. (0x046d) idProduct: M90/M100 Optical Mouse (0xc05a) bcdDevice: 0x6300 iManufacturer: 1 iProduct: 2 iSerialNumber: 0 bNumConfigurations: 1
At this point, I modified the keyboard Python to extract out the mouse data which is in the binary format of BYTE[Key State] BYTE[Signed X Offset] BYTE[Signed Y Offset]
. With all of the mouse movements extracted, I needed a way to visualize this data. My first thought was to draw the mouse movements on a canvas with a pen (or turtle). I have experience with Python’s Image Library (PIL) so I immediately reached for that.
Using the X, Y, and key state, I came up with the code below to draw and display an image:
#!/usr/bin/env python
# For2 - Google CTF 2016 by Grant for UFSIT
#
# Resources:
# http://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/
# https://stackoverflow.com/questions/13053443/drawing-a-line-on-an-image-with-pil
# https://stackoverflow.com/questions/20060096/installing-pil-with-pip
import binascii
import dpkt
import struct
import sys
from PIL import Image, ImageDraw
# Start the pcap file parsing
f = open(sys.argv[1], 'rb')
pcap = dpkt.pcap.Reader(f)
im = Image.new('RGBA', (1000, 1000), (0, 255, 0, 0))
points = []
state = []
# Then iterate over each USB frame
for ts, buf in pcap:
# We are interested only in packets that has the expected URB id
urb_id = ''.join(reversed(buf[2:10]))
if binascii.hexlify(urb_id) != 'fffffa80025896f0':
continue
data_length, = struct.unpack('<I', buf[0x17:0x17+4])
if data_length != 4:
continue
data = buf[0x1b:0x1b+4]
keys = struct.unpack("B",data[0])[0]
X = struct.unpack("b", data[1])[0]
Y = struct.unpack("b", data[2])[0]
points.append((X, Y))
state.append(keys)
cursor = (500, 500)
draw = ImageDraw.Draw(im)
for i,item in enumerate(points[1:]):
x = item[0]
y = item[1]
cursorNew = (cursor[0]+x, cursor[1]+y)
if state[i]:
draw.line((cursor[0], cursor[1], cursorNew[0],cursorNew[1]), fill=128)
cursor = cursorNew
im.show()
#im.save("for2_key.bmp")
Here is what it produced:
Flag: CTF{tHE_cAT_iS_the_cULpRiT}