捋一下知识点
🏷️ 例题:
| 20260202SHCTF(USB+鼠标流量)
| 20260202hgame(NewKeyboard)
| 更多 USB 流量案例见下方 [CISCN 2022] ez_usb 等
一、USB 协议基础概念
| 概念 | 说明 |
| Host | 主机(PC),发起请求的一方 |
| USB Device | 客户端设备(如键盘、鼠标、U盘) |
| Endpoint | 设备上的通信端点,分为 IN(设备→主机)和 OUT(主机→设备) |
| Interface Class | 设备类型,常见有: HID:Human Interface Device(键盘/鼠标) Mass Storage:U盘/移动硬盘 Printer:打印机 |
二、USB HID报文结构
一个典型的HID键盘报告是8字节的数据包
1 | Byte 0: Modifier Keys (Ctrl, Shift,Alt...) |
1 | 00 00 04 00 00 00 00 00 |
Byte0=0x00 无修饰键,Byte1=0x00 保留,Byte2=0x04 按 ‘A’,Bytes3~7 全 0 只按了一键。只有当字节不为 0 时才表示有效按键
三、关键字段
1. Modifier Keys 映射表(第 0 字节)
| Hex | Meaning |
| 0x01 | Ctrl |
| 0x02 | Shift |
| 0x04 | Alt |
| 0x08 | Win |
| 0x10 | Menu |
| 0x20 | Num Lock |
某位被置位即该修饰键被按住(例如 0x02 表示 Shift 被按住)
2. Key Code 映射表(第 2~7 字节)
最核心的部分,用于还原用户输入。
| Key Code (Hex) | Character / Action |
| 0x04 | A |
| 0x05 | B |
| 0x06 | C |
| … | … |
| 0x1F | 2 |
| 0x20 | 3 |
| 0x21 | 4 |
| 0x28 | n |
| 0x2a | [DEL] |
| 0x2B | 空格 |
| 0x32 | ~ |
| 0x33 | ; |
| 0x34 | ‘ |
| 0x36 | , |
| 0x37 | . |
注意:不是所有键都有映射,有些是特殊功能键(如 F1-F12)
四、Wireshark流量分析
1.定位USB HID
protocol列可以找USB``USBHID
过滤器可以用usbhid.data
2.根据设备地址分离流量
每个usb设备有一个唯一地址 格式是x.x.x
例如2.8.1``2.4.1``2.10.1
过滤器:usb.addr=="2.8.1"
或者usb.data_len == 8 and usb.src =="1.6.1"
有一个很奇怪的点 我在导出的时候必须导出到一个文件夹里 否则还是原始数据 试了好几次都这样
3.导出原始数据 tshark
注意要在官网下载wireshark然后要配一下PATH (之前不知道在哪下的,,没有tshark
"D:\Wireshark\tshark.exe" -r 流量包地址 -Y "usb.capdata" -T fields -e usb.capdata > 导出文件地址
如:"D:\Wireshark\tshark.exe" -r D:\luxluusb\2.4.1.pcapng -Y "usb.capdata" -T fields -e usb.capdata > D:\luxluusb\2.4.1.txt
-r 读pcap;-Y 过滤取 usb.capdata;-T fields 字段输出;-e usb.capdata 提取原始数据;> 导出到文件
五、py脚本
通用脚本
每行是标准USB HID报告描述符格式 共6字节(16hex字符)
1 | # -*- coding: utf-8 -*- |
-- coding: utf-8 --
“””
USB Keyboard HID 报文解析脚本
支持格式:
- 无分隔符:如 “0000120000000000”
- 冒号分隔:如 “00:00:12:00:00:00:00”
- 空格或其他分隔符(自动清理)
只提取主按键码(第3字节,偏移4-6),并严格忽略无效行。
未知键用 [unknown:0xXX] 标记,便于调试。
“””
USB HID Usage ID 到字符的映射(主键盘区,标准美式布局)
mappings = {
# 字母 A-Z
0x04: “A”, 0x05: “B”, 0x06: “C”, 0x07: “D”, 0x08: “E”, 0x09: “F”, 0x0A: “G”, 0x0B: “H”,
0x0C: “I”, 0x0D: “J”, 0x0E: “K”, 0x0F: “L”, 0x10: “M”, 0x11: “N”, 0x12: “O”, 0x13: “P”,
0x14: “Q”, 0x15: “R”, 0x16: “S”, 0x17: “T”, 0x18: “U”, 0x19: “V”, 0x1A: “W”, 0x1B: “X”,
0x1C: “Y”, 0x1D: “Z”,
# 数字 1-0
0x1E: "1", 0x1F: "2", 0x20: "3", 0x21: "4", 0x22: "5",
0x23: "6", 0x24: "7", 0x25: "8", 0x26: "9", 0x27: "0",
# 符号与功能键
0x28: "\n", # Enter
0x29: "<ESC>",
0x2A: "[DEL]", # Backspace
0x2B: "\t", # Tab
0x2C: " ", # Space
0x2D: "-", 0x2E: "=", 0x2F: "[", 0x30: "]", 0x31: "\\",
0x32: "~", # Non-US # (常作 `)
0x33: ";", 0x34: "'",
0x35: "`", # 部分系统中为 Non-US backslash,此处按常见用法设为 `
0x36: ",", 0x37: ".", 0x38: "/",
# 功能键(可选扩展)
0x39: "<CAPS>", 0x3A: "<F1>", 0x3B: "<F2>", 0x3C: "<F3>", 0x3D: "<F4>",
0x3E: "<F5>", 0x3F: "<F6>", 0x40: "<F7>", 0x41: "<F8>", 0x42: "<F9>",
0x43: "<F10>", 0x44: "<F11>", 0x45: "<F12>",
0x46: "<PRTSCR>", 0x47: "<SCROLLLOCK>", 0x48: "<PAUSE>",
0x49: "<INSERT>", 0x4A: "<HOME>", 0x4B: "<PGUP>",
0x4C: "<DEL>", # Delete
0x4D: "<END>", 0x4E: "<PGDN>",
0x4F: "<RIGHT>", 0x50: "<LEFT>", 0x51: "<DOWN>", 0x52: "<UP>",
}
def clean_and_extract_keycode(line):
“””
清理输入行,提取第3字节(USB HID 报文的主按键码)
支持格式:
- “0000120000000000”
- “00:00:12:00:00:00:00”
- “00 00 12 00 00 00 00”
返回 keycode (int) 或 None(无效行)
“””
line = line.strip()
if not line:
return None
# 移除所有非十六进制字符(保留0-9, a-f, A-F)
cleaned = ''.join(ch for ch in line if ch.lower() in '0123456789abcdef')
# 至少需要8个字符(4字节)才能取到第3字节(索引4-6)
if len(cleaned) < 8:
return None
try:
# 第3字节:从索引4开始取2个字符
key_hex = cleaned[4:6]
keycode = int(key_hex, 16)
return keycode
except ValueError:
return None
def main(input_file=’usbdata.txt’):
output = “”
with open(input_file, ‘r’, encoding=’utf-8’) as f:
for line_num, line in enumerate(f, 1):
keycode = clean_and_extract_keycode(line)
if keycode is None or keycode == 0:
continue # 跳过无效行或无按键
if keycode in mappings:
output += mappings[keycode]
else:
# 保留 unknown 并显示原始值,便于调试
output += f"[unknown:0x{keycode:02X}]"
print("Recovered keystrokes:")
print("-" * 40)
print(output)
print("-" * 40)
if name == “main“:
# 默认读取 ‘usbdata.txt’,你也可以改成 ‘2.8.1.txt’ 或其他
main(‘222.txt’)
1 |
output : 35C535765E50074A
1 |
output:526172211A0700[unknown]C[unknown]F907300000D00000000000000C4527424943500300000002[unknown]A000000[unknown]02B9F9B0530778B5541D33080020000000666C61672[unknown]E[unknown]747874[unknown]B9B[unknown]A013242F3A[unknown]FC[unknown]000B092C229D6E994167C05[unknown]A7[unknown]8708B271F[unknown]FC[unknown]042AE3D251E65536[unknown]F9A[unknown]DA87C77406B67D0[unknown]E6316684766[unknown]A86E844D[unknown]C81AA2[unknown]C72C71348D10C4[unknown]C[DEL]3D7B[unknown]00400700
1 |
|
提取后得到鼠标位移状态 进行绘图
1 | import matplotlib.pyplot as plt |

7724774CTF是F1111AG.jpg*的密码

010末尾获得flag

NSSCTF{this_is_rea1_fllllll11ag}
🏷️ 更多例题:
| 例题-USB键鼠流量
| 例题-USB键鼠流量
| 例题-USB键鼠流量
| 例题-USB键鼠流量
| 例题-USB键鼠流量
| 例题-USB键鼠流量
| 例题-USB键鼠流量
| 例题-USB键鼠流量