Hens can type?
Hens can type?
Platform: bluehensctf | Category: Forensics | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-04-21 | Status: Solved Techniques: scancode_mapping, usb_capdata_extraction, usb_hid_keyboard_decoding
Summary
Task: PCAPNG with USB traffic from usbmon0 containing HID keyboard data. Solution: Extract 8-byte HID reports from usb.capdata, decode USB keyboard scancodes to reconstruct typed text revealing the flag.
Hens can type? — BlueHens CTF 2026
Description
Analyze the USB traffic capture to find the flag.
Given a PCAPNG file challenge1.pcapng containing USB traffic captured from usbmon0.
Analysis
Initial reconnaissance with tshark/capinfos revealed USB interrupt traffic. The capture contains data from multiple USB devices, but the important packets came from USB source address 2.11.1 with endpoint 0x81.
The packets carry 8-byte payloads in the usb.capdata field — the standard format for USB HID boot keyboard reports:
Byte 0: Modifier keys (Shift, Ctrl, Alt, etc.)
Byte 1: Reserved (always 0x00)
Bytes 2-7: Up to 6 simultaneous key scancodes
Solution
- Extract USB HID keyboard data from the capture:
bash read-only • copy allowedtshark -r challenge1.pcapng -Y "usb.src == '2.11.1' && usb.capdata" -T fields -e usb.capdata
- Decode the HID keyboard scancodes. Each 8-byte report contains modifier flags and keycodes that map to characters:
python read-only • copy allowed#!/usr/bin/env python3 """USB HID Keyboard decoder for CTF challenges""" # USB HID keyboard scancode to character mapping SCANCODES = { 0x04: ('a', 'A'), 0x05: ('b', 'B'), 0x06: ('c', 'C'), 0x07: ('d', 'D'), 0x08: ('e', 'E'), 0x09: ('f', 'F'), 0x0a: ('g', 'G'), 0x0b: ('h', 'H'), 0x0c: ('i', 'I'), 0x0d: ('j', 'J'), 0x0e: ('k', 'K'), 0x0f: ('l', 'L'), 0x10: ('m', 'M'), 0x11: ('n', 'N'), 0x12: ('o', 'O'), 0x13: ('p', 'P'), 0x14: ('q', 'Q'), 0x15: ('r', 'R'), 0x16: ('s', 'S'), 0x17: ('t', 'T'), 0x18: ('u', 'U'), 0x19: ('v', 'V'), 0x1a: ('w', 'W'), 0x1b: ('x', 'X'), 0x1c: ('y', 'Y'), 0x1d: ('z', 'Z'), 0x1e: ('1', '!'), 0x1f: ('2', '@'), 0x20: ('3', '#'), 0x21: ('4', '$'), 0x22: ('5', '%'), 0x23: ('6', '^'), 0x24: ('7', '&'), 0x25: ('8', '*'), 0x26: ('9', '('), 0x27: ('0', ')'), 0x2c: (' ', ' '), 0x2d: ('-', '_'), 0x2e: ('=', '+'), 0x2f: ('[', '{'), 0x30: (']', '}'), 0x33: (';', ':'), 0x34: ("'", '"'), 0x36: (',', '<'), 0x37: ('.', '>'), 0x38: ('/', '?'), 0x31: ('\\', '|'), } def decode_hid_report(data: bytes) -> str: """Decode a single 8-byte HID keyboard report""" if len(data) < 3: return '' modifier = data[0] shift = bool(modifier & 0x22) # Left or Right Shift result = '' for keycode in data[2:8]: if keycode == 0: continue if keycode in SCANCODES: char = SCANCODES[keycode][1 if shift else 0] result += char return result # Process extracted HID data import subprocess output = subprocess.check_output([ 'tshark', '-r', 'challenge1.pcapng', '-Y', "usb.src == '2.11.1' && usb.capdata", '-T', 'fields', '-e', 'usb.capdata' ]).decode() typed_text = '' for line in output.strip().split('\n'): if not line: continue data = bytes.fromhex(line.replace(':', '')) typed_text += decode_hid_report(data) print(f"Typed: {typed_text}")
- The decoded keystrokes reveal the flag directly.