Tool - KBDscan
USB traffic scanner for keyboard detection.
Overview
Another day, another script! This time, I wrote a tool to analyze .pcap
files containing USB protocol packets to determine whether a USB keyboard is present among the captured devices. This script acts as a discovery tool by scanning USB traffic in a .pcap
file and identifying devices that match the characteristics of a USB keyboard.
I developed this tool after participating in irisCTF2025
, where one challenge involved extracting keystrokes from USB captures to retrieve the flag. It was a fun challenge, and if you’re curious, you can check out my write-up.
The script relies on the USB Human Interface Device (HID) specifications for keyboards to identify relevant packets in a capture. Specifically, it searches for packets that match the following criterias :
- Report Length: A USB keyboard typically sends 8-byte HID reports.
- Reserved Byte: The second byte of each report must be
0x00
, as this field is reserved in standard HID keyboard descriptors. - Empty Reports (Optional): Keyboards may send empty reports (all zeroes) when no keys are pressed, which can further confirm their presence.
You can find the source code on my Github.
Requirements
To use this script, make sure you haveTShark
installed, as it is required for processing the packet capture files.
Usage
To run the script, use the following command:
1
KBDscan.py [FILE]
[FILE]
is the path to the.pcap
file you want to analyze to check for the presence of USB keyboards.
By default, the script outputs a list of device addresses identified as potential keyboards in CSV
format. Each row corresponds to a detected device, allowing for easy parsing and further analysis.
Options
Summary
Option name | Usage | Description |
---|---|---|
Not empty | --not_empty | Includes devices that have never sent an empty report.. |
Render format | --r [RENDER] | Specifies the output format. |
Extract output | --e [OUTFILE] | Saves the results to the specified file. |
Index | --index | Adds an index when exporting results in CSV or JSON format. |
No space | --no_space | Removes leading and trailing spaces in the output. |
Quiet | --quiet | Suppresses the banner when running the script. |
Not empty
1
KBDscan.py [FILE] --not_empty
- Utility : By default, the script filters out devices that have never sent an empty report, as a standard keyboard used by a human will occasionally send empty reports when no keys are pressed. This behavior occurs because a user doesn’t type as fast as the computer reads input.
- Default : The default value is False (i.e., the script expects keyboards to send empty reports).
I added this option to account for devices like
Rubber Ducky
-style keystroke injectors. Since these act as keyboards but type at machine speed, they may never send empty reports. While I haven’t had the opportunity to test this behavior yet, this option is included to avoid missing such devices if my assumption is correct.
Render
1
KBDscan.py [FILE] -r or --render [RENDER]
- Utility : Changes the output format.
- Choices :
[RENDER]
can betxt
,csv
,json
ortab
. - Default : The default output format is
csv
.
Save output
1
KBDscan.py [FILE] -e or --extract [OUTFILE]
- Utility : Saves the results to the specified
[OUTFILE]
. The output format follows the one defined by the render option. - Default : If no output file is specified, results are printed to the standard output.
Other options
No space
1
KBDscan.py [FILE] --no_space
- Utility : Removes leading and trailing spaces from the output. Useful when redirecting results to a file or script.
- Default : By default, spaces are added for better readability in the standard output.
Add index
1
KBDscan.py [FILE] --index
- Utility : Adds an index column when exporting results in
CSV
orJSON
format. - Default : The index is not included by default.
Quiet
1
KBDscan.py [FILE] --quiet
- Utility : Suppresses the script’s banner when running.
- Default : The banner is displayed by default.
Example
For this example, I’ll quickly walk through the irisCTF2025
challenge I mentioned earlier. If you’re looking for a more detailed explanation—especially about the USB HID protocol—you can check out my write-up.
Since this script is designed as a discovery tool, we use it right away when first analyzing the .pcap file to identify potential USB keyboards.
1
2
3
4
5
KBDscan.py deldeldel.pcapng -q
# === Output ===
1.5.1
According to the script, the USB device with ID 1.5.1
appears to be a keyboard. We can now use this result to further analyze its transmitted packets and determine if any useful data—such as keystrokes—can be extracted.
Future Improvements
I’m considering expanding this script into a more complete workflow to:
- Extract potential USB devices from the
.pcap
file. - Decode keystrokes from detected USB keyboards.
- Save results to an output file for further analysis.
Additionally, I plan to test the script further and enhance its functionalities to make it more robust and reliable.
Conclusion
This is a simple yet effective script for quickly identifying USB keyboard devices in packet captures. The extended workflow I mentioned could be particularly useful for CTF players, as it would automate much of the analysis process.
In the future, I’d like to explore other USB device types, such as mice and storage devices, as I’ve come across some interesting scripts that analyze them.
Anyways, see you in the next one!
emree1