Wiki / Protocols

USB

Host-controlled bus where a device declares what it is through descriptors. The host trusts those claims, which is the whole attack surface.

USB descriptor hierarchy
Configuration
Interface: HID
IN interrupt EP
Interface: Mass storage
Bulk IN/OUT EP
Interface: CDC
Bulk + notify EP
Interface: Vendor
Custom EPs
During enumeration the host reads the device descriptor, then a configuration that groups one or more interfaces, each declaring a class (HID, mass storage, CDC, vendor) and its endpoints. The host loads a driver purely from these self-declared descriptors.

USB (Universal Serial Bus) is a host-controlled bus: a device attaches, and during enumeration it tells the host what it is through a tree of descriptors before any application data flows. The host then loads a driver based purely on those self-declared claims. That trust, the host believing whatever the device says it is, is the root of every USB attack.

What it is

USB is strictly host-centric: the host polls, the device answers, devices never initiate on their own. On plug-in, the host resets the port, assigns an address, and reads descriptors in a fixed hierarchy: the device descriptor (vendor/product ID, class), one or more configuration descriptors, each grouping interface descriptors (one per function, carrying a class code), and under each interface the endpoint descriptors that define the actual data pipes.

Element Detail
Enumeration host resets, addresses, and reads descriptors
Descriptors device to configuration to interface to endpoint
Classes HID, mass storage, CDC (serial), audio, vendor
Endpoints control (EP0) plus bulk / interrupt / isochronous

A single physical device can be composite: expose several interfaces at once (for example, a flash drive that is also a keyboard).

Why it matters

The host acts on the device's word. A gadget can present an HID keyboard interface and type commands the instant it is plugged in (BadUSB / HID injection), hide a second interface behind a benign-looking one, or feed the host malformed descriptors to trip driver parsing bugs in ring-0 code. Embedded products routinely leave a debug or DFU USB interface exposed, and mass-storage autorun paths remain a classic delivery vector.

How to work it

  1. Enumerate what is attached and read the full descriptor tree:
lsusb                       # list attached devices
lsusb -v -d 1234:5678       # full descriptors for one device
  1. Capture live USB traffic to understand a protocol or replay it:
sudo modprobe usbmon
# then select the usbmonX interface in Wireshark, or:
sudo cat /sys/kernel/debug/usb/usbmon/1u
  1. Emulate a device to test how the host reacts: a Facedancer/GreatFET, or Linux gadget mode (libcomposite / ConfigFS) on a Pi Zero or an OTG-capable board, lets you present arbitrary descriptors and classes.
  2. HID injection: script keystrokes on a Rubber Ducky, a Pi Zero in HID gadget mode, or an RP2040, to run commands on any host that trusts an attached keyboard.
  3. Fuzz descriptors (with a tool such as umap2) to hunt for host-driver crashes on malformed or contradictory descriptor trees.

Pitfalls

  • Emulation needs a UDC (USB device controller); a normal PC USB port is host-only and cannot present as a device without gadget-capable hardware.
  • Screen-lock and endpoint-allowlisting mitigations mean HID injection is not guaranteed; it depends on the target's posture.
  • lsusb -v needs privileges to read the full descriptor set; a truncated dump is a permissions artefact, not a device limit.
  • USB-C and higher-speed links add alternate modes and negotiation, but the classic descriptor-trust model still underpins the data path.

Further reading