USB PCAP Forensics: Graphics Tablet (NSEC CTF 2021 Writeup, Part 2/3)

Émilio Gonzalez
4 min readMay 24, 2021


Part 1: USB PCAP Forensics: Barcode Scanner (NSEC CTF 2021 Writeup, Part 1/3)

For this second challenge, we were given a different PCAP which can be found here.

Challenge introduction:

Goldsmiths’ Guild Part 2
I have heard that you have successfully gotten access into the Goldsmiths’ Guild. We’ll now need to take that covert action to the next step. Good luck.

The lobby is a small chamber with a second locked door and a desk on its side.
You hear from the other side of the door: “You need to sign the certificate”.
Upon inspection, you see a screen that the voice called the “certificate”. You find a jack and you plug your sniffer on it before leaving the guild.
You obtain Signatures Captures and go analyze them.

Flag 1: What are the vendor and the product name of the USB device? Format: flag-usb_[vendor][product]
Vendor hint: do not add Ltd., inc., corp., etc[/i]

Flag 2: Decode the device input.

Note: If you have not read part 1, it would be a good idea to do so, as I will not repeat explanations that overlap with it.

Exploring the PCAP

As with last time, let’s do a bit of exploration to see what kind of data we’re dealing with. Obviously, it’s another USB PCAP. We have more packets (~4400) that span over ~60 seconds. Finally, we see that there are bytes in the “HID Data” column:

The beginning of the PCAP also looks the same as part 1:

Great, so let’s look at the 2nd GET DESCRIPTOR Response DEVICE:

By googling, we find out that this device is a graphics tablet. Cool!

Flag 1: flag-usb_wacom_CTE-440

Since we saw earlier that this is also an HID device, let’s look at the GET DESCRIPTOR Response CONFIGURATION packet:

So it turns out that a graphics tablet is simply a fancy mouse from the perspective of the host machine.

Extracting and understanding the data

Let’s use the same technique as with part 1. Simple and effective.

By googling “USB mouse HID”, I found this very helpful link that describes the format of the mouse data:


This information is very straightforward. We need to extract three bytes to reconstruct what was “written” (1). I assumed that when the left button is pressed (2), it behaves like MSPaint and something is drawn. Notice in (3) that a mouse does not set the absolute position of the cursor, it moves it relative to its current position.

Using the same trick as in part 1, we see that only the 2nd, 3rd and 4th bytes seem to change from packet to packet. These are the 3 bytes mentionned in (1). Let’s extract them using Cyberchef:

Cyberchef is ❤

Now, onto the code!

Recovering what was written

For this part, I used the python-Pillow library to create an image from scratch. The code is pretty self-explanatory:

from PIL import Image

mouse_events = [(0x80, 0x01, 0xfd), (0x80, 0x01, 0xfe), ... (0x80, 0xff, 0xfa)]

# Make the image big because we don't know how long the message is
img ='RGB', (10000, 10000), color='white')
canvas = img.load()

# Start the cursor in the middle of the canvas
mouse_x = 5000
mouse_y = 5000

for data in mouse_events:
# Get the left mouse button status
left_button_pressed = data[0] & 0b00000001

# Get the mouse movement in x and y
x_offset = int.from_bytes(data[1:2], "big", signed=True)
y_offset = int.from_bytes(data[2:3], "big", signed=True)

mouse_x += x_offset
mouse_y += y_offset

if left_button_pressed:
# These two for loops are to make the pixels thicker
for i in range(5):
for j in range(5):
# Write a black pixel on the canvas
canvas[round(mouse_x) + i, round(mouse_y) + j] = (0, 0, 0)

# Save the image to disk"final.png")

We run this script, open “final.png” and zoom in to see this:



Flag 2: flag-sir_mon3y_l4und3ring

This was also a great challenge that built on what we learned in part 1, but required a little bit more fancy parsing and using an image canvas to get the flag.

Stay tuned for part 3!



Émilio Gonzalez

Blue team analyst in Quebec, Canada. Passionate about cybersecurity and urbanism. Twitter: @res260