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:

For2 Python PIL drawing

Flag: CTF{tHE_cAT_iS_the_cULpRiT}