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

Exploring the data

The first thing I like to do when I open a PCAP is to understand how much data is exchanged, how many machines are involved and for how long. For larger PCAP, Wireshark has nice features in the “Statistics” menu, but since this PCAP is small (34ko), simply scrolling down to the last packet does the trick:

Don’t forget to create a separate profile (bottom right)for USB packets, as interesting columns and settings will differ from network-based PCAP
Two identical “handshakes”
Page 11

Extracting and understanding the data

So we want to see the data that was scanned by the barcode scanner, which means see what characters were “typed” by the device. The rest of the PCAP consists of “URB_INTERRUPT in” packets. Let’s filter on packets sent by the scanner by right-clicking the source of a packet:

Easy way to filter when you don’t remember the exact filter name
Create a new display column easily with this one weird trick
Export as CSV
The “fork” operation splits the input into multiple inputs, so each subsequent operation is done on the subset of the input. The “Merge delimiter” dictate what is to be appended between each input when they are merged together in the output box.

Recovering what was scanned

To know which key represented which character, I googled “USB HID Keyboard Key Codes” and found this nice Gist. Great, we now have every ingredient needed to recover the data, let’s write the code:

# The data from Cyberchef
chars = [("00", "16"), ("00", "0c"), ... ("00", "04"), ("00", "28")]

# Association between code and char
map = {
"04": "a",
"05": "b",
"06": "c",
"07": "d",
"08": "e",
"09": "f",
"0A": "g",
"0B": "h",
"0C": "i",
"0D": "j",
"0E": "k",
"0F": "l",
"10": "m",
"11": "n",
"12": "o",
"13": "p",
"14": "q",
"15": "r",
"16": "s",
"17": "t",
"18": "u",
"19": "v",
"1A": "w",
"1B": "x",
"1C": "y",
"1D": "z",
"1E": "1",
"1F": "2",
"20": "3",
"21": "4",
"22": "5",
"23": "6",
"24": "7",
"25": "8",
"26": "9",
"27": "0",
"2C": " ",
"28": "\n",
"2D": "-",
"34": "'",
"36": ",",
"2E": "=",
"33": ";",

phrase = ""
for char in chars:
if char[1].upper() in map:
# If LShift is not pressed
if char[0] == "00":
phrase += map[char[1].upper()]
# If LShift is pressed
actual_char = map[char[1].upper()]
upper_map = {
"-": "_",
"0": ")",
"9": "(",
# For debug purposes
if char not in upper_map:
print(f"skip {char}")
# Add a char to be printed
actual_char = upper_map[char]
phrase += actual_char.upper()
# For debug purposes
print(f"skip {char}")



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Émilio Gonzalez

Émilio Gonzalez


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