Introduction
Riverside was an original forensic challenge at Boston Key Party 2015.
omg tha NSA hacked my super secret login, I caught them exfillin this pcap, am I t3h fuxxed?
We are given a pcap-ng file, after opening with Wireshark we observe it only contains USB traffic. The attacker probably used an HID to exfiltrate informations from the victim.
Filtering
The first step is to identify the USB devices, maybe it will help us find suspicious behaviours.
We apply the following filter to Wireshark to display descriptor response from devices.usb.bDescriptorType && usb.urb_type == 0x43
It looks like there are seven different USB devices.
- Logitech M-BJ58/M-BJ69 Optical Wheel Mouse
- Linux Foundation 3.0 root hub
- Intel Integrated Rate Matching Hub
- Linux Foundation 2.0 root hub
- Acer Integrated Camera
- Intel 7260AC Bluetooth
- Linux Foundation 2.0 root hub
After further investigation we found out that the only device that actually exchange a lot of data is the USB mouse.
You can use the following Wireshark filter to only display the interesting packets.usb.data_flag == "present (0)" && usb.device_address == 12
Decoding mouse data
To decode the mouse data, we fist have to know how it is encoded. It is actually very simple to understand, even without any documentations.
The carried data is 4 bytes the first one indicates the mouse status, the second one the direction on the X axis, the second the direction on the Y axis and the last one is for the mouse wheel.
We will convert the pcap-ng to a pcap with Wireshark and create a Python script to read the data from the capture file.
#!/usr/bin/env python
import struct
import Image
import dpkt
def print_data(pcap, device):
for ts, buf in pcap:
device_id, = struct.unpack("b", buf[0x0B])
if device_id != device:
continue
data = struct.unpack("bbbb", buf[-4:])
print(data)
if __name__ == "__main__":
f = open("usb.pcap", 'rb')
pcap = dpkt.pcap.Reader(f)
print_data(pcap, 12)
f.close()
Output
(0, 0, 0, 0)
(0, -3, 2, 0)
(0, 0, 0, 0)
(0, -2, 2, 0)
(0, 0, 0, 0)
(0, -4, 2, 0)
(0, 0, 0, 0)
(0, -4, 1, 0)
…
Mapping mouse position
The next step was to map the mouse position, we create a blank image and put pixels on the mouse coordinates and black squares on mouse clicks.
#!/usr/bin/env python
import struct
import Image
import dpkt
INIT_X, INIT_Y = 100, 400
def print_map(pcap, device):
picture = Image.new("RGB", (1200, 500), "white")
pixels = picture.load()
x, y = INIT_X, INIT_Y
for ts, buf in pcap:
device_id, = struct.unpack("b", buf[0x0B])
if device_id != device:
continue
data = struct.unpack("bbbb", buf[-4:])
status = data[0]
x = x + data[1]
y = y + data[2]
if (status == 1):
for i in range(-5, 5):
for j in range(-5, 5):
pixels[x + i , y + j] = (0, 0, 0, 0)
else:
pixels[x, y] = (255, 0, 0, 0)
picture.save("riverside-map.png", "PNG")
if __name__ == "__main__":
f = open("usb.pcap", "rb")
pcap = dpkt.pcap.Reader(f)
print_map(pcap, 12)
f.close()
Result
This definitely looks like a keyboard, it is probably the windows on screen keyboard. From this point we could read the typed letters one by one but it would take too much time so let's create a script to automate the process.
Getting the flag
I created a template representing an English keyboard.
The script below will crop a 50px square on the position of each click and save it in a new file.
#!/usr/bin/env python
import struct
import Image
import dpkt
INIT_X, INIT_Y = 100, 400
def print_map(pcap, device):
picture = Image.open("riverside-template.png")
pixels = picture.load()
x, y = INIT_X, INIT_Y
for ts, buf in pcap:
device_id, = struct.unpack("b", buf[0x0B])
if device_id != device:
continue
data = struct.unpack("bbbb", buf[-4:])
status = data[0]
x = x + data[1]
y = y + data[2]
if (status == 1):
picture.crop((x - 25, y - 25, x + 25, y + 25)).save("letter-" + str(ts) + ".png", "PNG")
if __name__ == "__main__":
f = open("usb.pcap", "rb")
pcap = dpkt.pcap.Reader(f)
print_map(pcap, 12)
f.close()
The last step is to concatenate all the pictures in the right order and you should get the flag.