USB Research
This post is a compilation of my notes covering all things related to USB and my research into the security considerations surrounding the USB protocol and devices. It's been updated to present the notes in a more practical order, one you could follow if you were simply curious on the topic. This research exists to augment everything that's already in MITRE ATT&CK.
After reading, you should have an understanding of:
- How USB works (protocol and devices)
- USB-based attacks
- Safely enumerating USB devices
- Baselining, detection, and mitigating USB threats
This is primarily targeting Linux and Windows machines.
References
This research was started using the following references.
- MITRE ATT&CK Removeable Media Overview
- USB Device Class Codes
- USBGuard
- USBGuard Class Codes Rule Implementation
- USB DFU Specifications
- Example Showing Steps Taken In Writing BadUSB Firmware to RubberDucky Device
- Flashrom (Read, Write, Edit firmware)
- Linux Kernel USB Authorization
- Systemd-Mount
- Kali forensic menu hooks
- xfce Docs: Removable Media
- autofs daemon
- CISA: Removeable media best practices
- CISA: 0-Day - Downloading a payload when Windows Explorer processes a crafted shortcut
Utilities to Get Started
USBGuard is not strictly necessary, but is universally available regardless of the desktop (or lack of) environment.
# Install, on Debian-family OS's it should automatically approve
# all actively connected USB controllers and devices at the time
# of install
sudo apt install usbguard
# List all devices and their information
usbguard list-devices
# Monitor bus activity
usbguard watch
# Permanently allow a device after reviewing its capabilities
sudo usbguard allow-device -p <id>
These Linux utilities are used to interface with and manipulate USB devices and their embedded firmware:
sudo apt install dfu-util
sudo apt install dfu-programmer
sudo apt install flashrom
The following filesystem locations relate to USB logs or devices:
# Serial Devices
/dev/ttyUSB*
# Kernel Files
/sys/bus/usb/devices/*
# Logs
/var/log/kern.log
/var/log/syslog
/var/log/user.log
How USB Works
Wikipedia has a full history on USB and USB connections.
Generally, USB is handled first via the machine's firmware, then the OS's kernel, before anything in user-land sees it. USB device class codes describe what the device can do. CDC, DFU mode, and any unique classes with interesting capabilities will be described here.
USB CDC
The USB Communications Device Class includes { 02:??:?? } for CDC communication and {0a:??:?? } CDC data. It's best described by Wikipedia:
USB CDC
USB communications device class (or USB CDC) is a composite Universal Serial Bus device class. It is most commonly used for computer networking devices akin to a network card, providing an interface for transmitting Ethernet or ATM frames onto some physical media. It is also used for modems, serial ports, ISDN, fax machines, and telephony devices that perform regular voice calls.
Effectively this means USB-to-ETH adapters, things like Alfa Wireless cards, Meshtastic Devices with a serial port exposed for firmware updates, or even the WiFi Pineapple Pager which uses a LAN-over-USB interface to provide "offline" network access and management of the device.
Interestingly Microsoft has it's own proprietary protocol separate from CDC, which is called Remote Network Driver Interface Specification (RNDIS). It's meant to function similarly and appears to be supported in most Unix-like operating systems (for now).
Attack Vector
We can assess the risks associated with this device class in two ways:
- How does the protocol work?
- What exploits against this class exist and how do they work?
AI Usage
Claude Sonnet 4.5 (Anthropic). "CDC Subclass Risk Categorization." Claude.ai chat session, 24 Jan. 2026.
AI was used to source + search through documentation and organize this section. All work was manually reviewed and adjusted before committing.
Subclasses and Functionality
The usb.org Class definitions for Communication Devices 1.2 documents each subclass of the CDC device class and what they can do. The errata document provides a quick reference for the following data:
- CDC Communication on the website provides the overview for the base class (
{02:??:??}) CDC120-Errata1.pdfIssue B breaks down the Subclass CodesCDC120-Errata1.pdfIssue C covers Data Interface Class Protocol CodesCDC120-Errata1.pdfIssue D containsbDescriptorSubType in Communications Class Functional DescriptorsCDC120-Errata1.pdfIssue E details all Class Specific Request Codes
All of this information is expanded on in CDC120-20101103-track.pdf Section 4.0 "Class-Specific Codes". The section below was organized based on risk and attack options associated with each subclass.
Ethernet Networking Control Model (ECM) - 0x06
Creates kernel network interface automatically, bypasses userspace mediation.
- USBGuard pattern:
02:06:00- "The Data Class Interface Descriptor protocol code for all Networking Control Models is 00h." - Section 3.3 of ECM120.pdf
- Attack surface: Kernel network and USB stack, routing tables, DNS, think poisoning and untrusted networks
- Common in: USB-to-Ethernet adapters, smartphone tethering
- See also: Wikipedia: Ethernet-over-USB
Section 3.3 of also states that "The Data Class interface of a networking device shall have a minimum of two interface settings.". This means a common pattern you'll see is:
# 2x 0a:??:??, one for INPUT, and one for OUTPUT of network data
{ 02:06:?? 0a:??:?? 0a:??:?? }
Practically, outside of exploits targeting the kernel's USB and networking stacks, this works the same as connecting to an untrusted network.
The major difference here is rather than an existing eth0 coming online and receiving assignments via DHCP, the Linux kernel creates a new interface for this USB connection. This is worth considering if your firewall rules are per-interface and not global.
Network Control Model (NCM) - 0x0D
Optimized ECM variant. Same kernel exposure, better throughput.
- USBGuard pattern:
02:0d:* - Attack surface: Same as ECM
- Common in: Modern mobile devices, LTE modems
Ethernet Emulation Model (EEM) - 0x0C
Simplified Ethernet-over-USB.
- USBGuard pattern:
02:0c:* - Attack surface: Same as ECM
ATM Networking Control Model - 0x07
ATM network interfaces (legacy).
- USBGuard pattern:
02:07:*- "The Data Class Interface Descriptor protocol code for all Networking Control Models is 00h." - Section 3.3 of ATM120.pdf
- Attack surface: Similar to ECM
Similar to the other networking subclasses in practically every way. Two things that stand out are the size limit on data segments:
In the case of AAL5 SDU exchanges, the segment size could be up to 64K bytes in length, and is a function of device buffering capacity and the results of end-to-end negotiation with Q.2931.
and the data type being "cells" instead of ethernet frames:
An ATM USB device is used to move ATM cells or AAL5 SDUs to and from the host. The segmentation and re-assembly (SAR) function in the ATM adaptation layer may be implemented on the host, and not necessarily on the device.
Abstract Control Model (ACM) - 0x02
Serial port emulation. Userspace mediation via /dev/ttyACM*.
- USBGuard pattern:
02:02:* - Attack surface: Applications interacting with serial ports (automatically or manually), but similar to SSH in terms of manual interaction over
screen - Common in: Arduino, modems, debug consoles
This subclass does not have the capability to automatically execute anything on your system. It's effectively an open pipe to transfer data, so it helps to imagine this as similar to SSH; there can be exploits that affect the connecting client's terminal itself, though generally a compromised server cannot send arbitrary commands back to a connecting client.
However, the most common results for attack paths on ACM and serial communication ports include UDEV rules or services like ModemManager that automatically interact with the device. Ultimately having an ACM data pipe opened is not a huge risk to your host without interaction. Connecting a device with this interface to the host momentarily (allowing it in USBGuard) to pass it through to a VM is relatively safe (ignoring exploits that target the host's kernel). There in the VM, any software that interacts with the data pipe may be a target, but the point is the step required to attach the device to a VM is often OK to take.
Direct Line Control Model (DLCM) - 0x01
TO DO
Telephone Control Model (TCM) - 0x03
TO DO
Multi-Channel Control Model (MCCM) - 0x04
TO DO
CAPI Control Model - 0x05
TO DO
Wireless Handset Control Model (WHCM) - 0x08
TO DO
Device Management - 0x09
TO DO
Mobile Direct Line Model (MDLM) - 0x0A
TO DO
OBEX - 0x0B
TO DO
RESERVED (future use) - 0Dh-7Fh
TO DO
RESERVED (vendor specific) - 80-FEh
TO DO
Exploits
To get a sense of what's possible, a brief triage across various vulnerability platforms can be done. Both "usb" + "cdc" were searched, along with "usb" + "communications device class".
- Results in the NVD for "USB CDC" show 19 records since 2013
- Searching github.com/trickest/cve shows 11 results with 7 unique hits related to USB CDC
- CVE.ORG's "usb cdc" records mirror both of the previous sources, with 12 results
Common attack vectors target the Linux kernel, and in many cases, require the USB device itself to have specific or crafted properties that cause errors in the kernel when parsing the descriptors or data sent by the device.
Segment Size
Sections 3.3.1 and 3.3.2 of ECM120.pdf detail it's both, the host's and USB device's job to agree on a size limit for the data being sent. Exploits attacking the kernel here rely on the host's kernel not properly handling this.
Azure RTOS USBX is a unique out of all the results, as it's a component of a real-time operating system (now maintained by Eclipse ThreadX) that had the only RCE documented. The remaining results targeted the Linux kernel, no Windows or macOS results were discovered.
None of these have a fully functioning or practical proof-of-concepts ready for us in a real world engagement. Of all the CVE records returned from the 3 sources above, only one had a proof-of-concept in the form of a reproducible bug:
- Project Zero Issue 395107243 for CVE-2025-21704,
cdc_acm_oob_write.cand instructions to reproduce the issue are shared.dmesgcatches and logs the result in this case.
Patch Notes
The remaining records only linked to patch notes. Not every note was manually reviewed, but to exhaust all possibilities they should be, in addition to your own fuzzing and debugging of valid targets in a lab environment.
The most interesting patch summary was pulled by GPT 5.2's deep research mode from Wiz for CVE-2025-21704, in this case /dev/ttyACM* must be opened by userspace. However, ModemManager (another Linux kernel component) will automatically open these types of devices depending on the device.
DFU Mode
Device Firmware Upgrade (DFU) mode exposes the following class codes: { FE:*:* }, { FE:01:* }, { FE:01:01 }
| Base Class | Sub Class | Protocol |
|---|---|---|
FE |
01 |
01 |
This is how DFU mode works:
- While being upgraded, the USB device cannot act as a USB device (if it was a keyboard, it loses keyboard functionality during DFU mode)
- Linux requires dfu instrumentation locally (
dfu-programmer,dfu-util) to flash chips- These tools can be embedded in other tools (e.g. a program to flash updates to your USB device)
- They often require root privileges to perform their functions
- In any case, the tools must exist locally in some way for the device to enter DFU and be modified
- The device hash will change in USBGuard
- The device class code(s) will change if the firmware alters functionality
- Vendor, manufacturer, serial number, and other index string descriptors can be changed
USB-based Attacks
Replication Through Removable Media: T1091
Adversaries may move onto systems, possibly those on disconnected or air-gapped networks, by copying malware to removable media and taking advantage of Autorun features when the media is inserted into a system and executes. In the case of Lateral Movement, this may occur through modification of executable files stored on removable media or by copying malware and renaming it to look like a legitimate file to trick users into executing it on a separate system. In the case of Initial Access, this may occur through manual manipulation of the media, modification of systems used to initially format the media, or modification to the media's firmware itself.
Mobile devices may also be used to infect PCs with malware if connected via USB. This infection may be achieved using devices (Android, iOS, etc.) and, in some instances, USB charging cables. For example, when a smartphone is connected to a system, it may appear to be mounted similar to a USB-connected disk drive. If malware that is compatible with the connected system is on the mobile device, the malware could infect the machine (especially if Autorun features are enabled).
Communication Through Removable Media: T1092
Adversaries can perform command and control between compromised hosts on potentially disconnected networks using removable media to transfer commands from system to system. Both systems would need to be compromised, with the likelihood that an Internet-connected system was compromised first and the second through lateral movement by Replication Through Removable Media. Commands and files would be relayed from the disconnected system to the Internet-connected system to which the adversary has direct access.
AutoPlay/Exec/Run
AutoRun, AutoExec, and AutoPlay are features that will automatically execute data from removable media when it's mounted. This primarily affects Windows and some Linux Desktop environments. macOS does not appear to have this issue.
On Windows this behavior is split into both, AutoRun and AutoPlay.
Using and Configuring Autoplay is specifically for media files (e.g. music) rather than applications.
AutoRun is the mechanism through which, if enabled, external media can execute anything described in the Autorun.inf Entries, which is a text file in the root of the external media drive. These are just ini-like key/values interpretted by Windows if it's allowed to AutoRun external media. This example illustrates what these files can contain, and what each key means. This is useful for both forensics and understanding their offensive capabilities.
With Linux, this behvaior depnends on your desktop environment.
| Desktop Environment Docs | Autorun Optional | Default Setting | Prompt Required |
|---|---|---|---|
| Windows: AutoRun.INF | ⚠️ | Disabled by Default via Patch | NO |
| GNOME: Files & Autorun | ✅ | OFF | YES |
| KDE: Removable Devices | ❌ | N/A | N/A |
| xfce: Managing Removable Drives and Media | ✅ | OFF | YES |
BadUSB
From the Flipper Docs
A BadUSB device can change system settings, open backdoors, retrieve data, initiate reverse shells, or do basically anything that can be achieved with physical access. It is done by executing a set of commands written in the Rubber Ducky Scripting Language, also known as DuckyScript. This set of commands is also called a payload.
BadUSB attacks were made popular by Hak5's Rubber Ducky, which is a USB drive designed to act with HID (keyboard and mouse) capabilities via the device's firmware. The dead giveaway is a device having the class codes for both, something else that's the intended purpose of the device (e.g. mass storage, WiFi adapater, etc) and HID (03:xx:xx) when you aren't expecting it to have typing and mouse capabilities.
BadUSB devices can include anything with a USB port:
- External drives
- KB/Mouse (yes, with hidden payload injection)
- WiFi, bluetooth adapters
- Power brick with USB ports
- USB hub
- ...and more!
DuckyScript being a programmable language means you can embed logic for delayed execution. A sneaky vector would be to delay for hours, days, or weeks depending on the device, and only make small modifications. This is why access-controls based on device class codes and hashes is the best detection and mitigation here.
Can My USB Become Bad?
An existing USB device can become a BadUSB if the firmware is modifiable. Typically, this requires that the device must support DFU mode, and subsequently be set to DFU mode to receive a firmware controller update before reverting from DFU mode back to "normal" operating mode, only now that includes HID payload injection.
Flashing firmware often requires the flashing tools exist locally, or via web-USB in your browser, and prompt you for root or sudo privileges.
If there's an undocumented way to modify the USB device's firmware, that's of course also possible, but becomes way less common and requires a targeted effort even with all the right tools and privileges locally available to modify the device, either in a target environment or ahead of time by the adversary.
You can see how common these are in GitHub topics for BadUSB payloads.
Firmware Attacks
These were described briefly in the previous section on BadUSB, and include the notes above on DFU mode.
Relevant Tools
Devices like the Bash Bunny appear to have the capability to fake or emulate any USB class interface. These will need to be reviewed here.
It's less likely, but possible to do remotely, within a target environment, if all the right tools and access are available.
Even more unlikely is the firmware of the USB device having a payload designed for a target's hardware + firmware layer, or the kernel components that handle USB devices. More research is needed here.
Examining Untrusted Devices
AI Usage
Claude Sonnet 4.5 (Anthropic). "CDC Subclass Risk Categorization." Claude.ai chat session, 24 Jan. 2026.
AI was used to suggest and quickly determine what native Linux commands and utilities work well for reviewing USB behavior on a system.
dmesg
Follow the dmesg log and grep for "usb" events.
sudo dmesg -wH | grep -i usb
This is a relatively low-noise feed of events. USBGuard details are here as well, in terms of Authorized to connect vs Device is not authorized for usage.
Here's example output from a WiFi Pineapple Pager, with some fields redacted.
[Jan24 12:00] usb 3-1: new high-speed USB device number 7 using xhci_hcd
[ +0.000000] usb 3-1: New USB device found, idVendor=<redacted>, idProduct=<redacted>, bcdDevice=<redacted>
[ +0.000000] usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=<redacted>
[ +0.000000] usb 3-1: Product: USB 10/100/1000 LAN
[ +0.000000] usb 3-1: Manufacturer: Realtek
[ +0.000000] usb 3-1: SerialNumber: <redacted>
[ +0.000000] usb 3-1: Device is not authorized for usage
# Here USBGuard allowed the device
[ +0.000000] usb 3-1: authorized to connect
[ +0.000000] usbcore: registered new device driver r8152-cfgselector
[ +0.000000] r8152-cfgselector 3-1: reset high-speed USB device number 7 using xhci_hcd
[ +0.000023] usbcore: registered new interface driver r8152
[ +0.000000] usbcore: registered new interface driver cdc_ether
[ +0.000000] usbcore: registered new interface driver r8153_ecm
journalctl
Similar to dmesg, with timestamps and slightly varied event reporting. This is also a low-noise log to view.
sudo journalctl -kf
Here you'll likely see the new network interface your kernel creates, and all activity associated with it.
udevadm
This log output is very verbose, but focused. This will monitor all UDEV events and print the full properties associated with them. Useful for reviewing additional USB details such as vendor, device model, systemd and the various dev paths associated to the device.
sudo udevadm monitor -p
Usbguard
On a system running USBguard, you can simply connect the external device to see if it has a USB interface and what it's capable of. This is an easy way to confirm devices like chargers or power bricks are just that, and not anything more.
usbguard watch
Once connected, details and capabilities will be printed to your terminal window without giving the device any USB capabilities on your system. Details also include a hash of the device's interface, so you could even detect firmware changes to devices previously approved in USBguard this way; or establish a baseline hash for new and trusted devices.
Kali Linux
Kali makes this easy by having forensics tools and good defaults built-in via forensics mode.
- Kali live usb -> forensic mode
- Live environment kernel and files are read-only via Squashfs
- Does not automatically mount any storage devices by default
Risk
Regarding the sample device under examination attacking the Kali live USB or other firmware during review:
- Kali Live in forensic mode does not do anything without user interaction (think AutoRun or AutoMount)
fwupdmgr get-devices --show-all-devices > devices.outcan generate a summary of the internal device details before you startusbguard list-devicesand commands likelsusbcan also give you a baseline before starting- Ideally you're on a dedicated test machine, like a Raspberry Pi 5, that has a signed chain of firmware
When you're ready to start ensure USBGuard is installed:
sudo apt install -y usbguard
Ensure after install there is no 5: allow id *:* label "GNOME_SETTINGS_DAEMON_RULE" or similar present.
sudo usbguard list-rules
In the above example the rule id is 5. Remeove this rule with:
sudo usbguard remove-rule 5
Open a new terminal window and set usbguard daemon to watch:
usbguard watch
From here you're ready to mount the device you're examining. This will print the devices manufacturer ID, serial number, name, a hash of the device tied to its firmware, hash of the parent connector (the usb port on the system), a list of interfaces, and connection type if available.
Example output:
2: block id 1234:abcd serial "123456789" name "USB Worm Device" hash "1234567890abcdefghijklmnopqrstuvwxyz=" parent-hash "1234567890abcdefghijklmnopqrstuvwxyz=" via-port "1-1" with-interface {08:01:02 03:01:23} with-connect-type "unknown"
As mentioned above, seeing interfaces 08:*:* and 03:00:* aka 'USB Mass Storage' and 'HID/Keyboard' together on a simple flash drive indicates a keyboard interface or similar functionality was added to the firmware. It's fair to assume this device can or will attempt to autotype commands once mounted.
Forensic Mode (noautomount)
What is Kali doing behind the scenes to achieve this? And can Ubuntu live do the same? (Short answer is yes)
Looking at kali-config/common/hooks/live/forensic-menu.binary shows that noautomount is a live hook, but where is that parameter being read and by what?
Is the following the same as setting...
/org/gnome/desktop/media-handling/automount -> false
/org/gnome/desktop/media-handling/automount-open -> false
/org/gnome/desktop/media-handling/autorun-never -> true
...in a GNOME environment? Or is more happening at the kernel level to prevent any read/write operations on external media?
From systemd-mount, the --automount and --discover flags seem to handle removable media, however it's unclear if these options are about the same thing kali is doing in forensic mode, as they facilitate connections with the kernel happening AFTER user opts to open the media device in the file system (my interpretation).
Manually enabling auto-mounting of media in the Thunar file explorer enables this feature once you log out and back in during a live session - this seems to indicate the noautomount hook sets a preference, similar to setting site preferences with dconf in /etc/dconf/db/site.d/locks
Looking in other relevant places, there are no configurations on Kali Live for the following:
/etc/fstab/etc/udev/rules.d/noautois not a kernel parameter or a udisks2 parameter...
See:
man systemd.mountman systemd.automountman systemd-mount
Example from the systemd Manual
Use a udev rule like the following to automatically mount all USB storage plugged in:
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", \
RUN{program}+="/usr/bin/systemd-mount --no-block --automount=yes --collect $devnode"
Configurations to /etc/udisks2/udisks2.conf are the same for Kali Live and Ubuntu's defaults
How does this all compare with an Ubuntu / GNOME environment configured with the following?
cat /etc/dconf/db/site.d/00_media-handling
# Disable autorun and automount of software and external media
[org/gnome/desktop/media-handling]
autorun-never=true
automount=false
automount-open=false
cat /etc/dconf/db/site.d/locks/media-handling
# Disable autorun and automount of software and external media
/org/gnome/desktop/media-handling/automount
/org/gnome/desktop/media-handling/automount-open
/org/gnome/desktop/media-handling/autorun-never
Can the same be achieved? We can review the relevant log files to confirm:
Running the following...
tail -f /var/log/kern.logtail -f /var/log/syslogtail -f /var/log/user.log
...reveals filesystems are not mounted until explicitly mounted by the user.
Both Kali in forensics mode and Ubuntu with AutoMount/Open disabled, output the same logging data.
You can further verify this in the GUI by launching disks and reviewing the status of the device, this will show it as unmounted or (encrypted if applicable).
Detection & Mitigation
This section covers defensive strategies for combatting USB threats.
USBGuard
USBGuard is by far the most robust tool for protecting your unix-like system(s) from USB-based threats. It will prevent unknown, or unauthorized devices from being seen by any system driver by using the kernel to allow or deny it based on attributes and rules.
The Arch Linux Wiki has a similar write up to this one, with references to the implementation in GNOME that will be shared below.
# Install, on Debian-family OS's it should automatically approve
# all actively connected USB controllers and devices at the time
# of install
sudo apt install usbguard
# List all devices and their information
usbguard list-devices
# Monitor bus activity
usbguard watch
# Permanently allow a device after reviewing its capabilities
sudo usbguard allow-device -p <id>
That's all there is to using it. It's recommended to perform this install on a test system first using the Linux distribution you intend to run on real hardware. This way you can catch if anything goes wrong during install or configuration. USBGuard runs just fine on QEMU / virt-manager, VMWare, VirtualBox, Hyper-V, and similar virtualization software that supports USB pass-through.
USB != SD
Interestingly enough this does not block SD cards, or anything that isn't a USB device.
USBGuard on GNOME
GNOME had a research project in 2018 design to increase USB protection. This appears to have resulted in the following settings being added to GNOME's system key/value store.
USBGuard seems to be required for this work. This just allows you to handle USBGuard via GNOME's settings if you want. To enforce these via dconf or gsettings, follow similar steps to those detailed below in the Disabling Autorun, Autoplay, and Automount Linux section.
Device Management via Group Policy
Preventing installation of prohibited devices via Group Policy can be used to emulate what USBGuard does, but on Windows, with the native Windows tools. This can be complicated, but detailed instructions are available for a number of scenarios.
- Scenario #1: Prevent installation of all printers
- Scenario #2: Prevent installation of a specific printer
- Scenario #3: Prevent installation of all printers while allowing a specific printer to be installed
- Scenario #4: Prevent installation of a specific USB device
- Scenario #5: Prevent installation of all USB devices while allowing an installation of only an authorized USB thumb-drive
Layers of Connectivity
Some device in the system have several layers of connectivity to define their installation on the system. USB thumb-drives are such devices. Thus, when looking to either block or allow them on a system, it's important to understand the path of connectivity for each device. There are several generic Device IDs that are commonly used in systems and could provide a good start to build an 'Allow list' in such cases. See below for the list:
PCI\CC_0C03; PCI\CC_0C0330; PCI\VEN_8086; PNP0CA1; PNP0CA1&HOST (for Host Controllers)/ USB\ROOT_HUB30; USB\ROOT_HUB20 (for USB Root Hubs)/ USB\USB20_HUB (for Generic USB Hubs)/
Specifically for desktop machines, it's very important to list all the USB devices that your keyboards and mice are connected through in the above list. Failing to do so could block a user from accessing its machine through HID devices.
Different PC manufacturers sometimes have different ways to nest USB devices in the PnP tree, but in general this is how it's done.
Generally you'll need to enumerate USB devices with either Get-WmiObject Win32_USBControllerDevice ... or cmd.exe /c pnputil. This is detailed over in the Device Management section of the Windows notes.
Disabling Autorun, Autoplay, and Automount
Windows
SANS Blog: Configure Windows Forensic Workstations is a great reference for Windows here in general.
Disable AutoRun:
# HKLM
reg add HKLM\Software\Microsoft\Windows\CurrentVersion\policies\Explorer /v NoDriveTypeAutoRun /t REG_DWORD /d 0xFF /f
# HKCU
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\policies\Explorer /v NoDriveTypeAutoRun /t REG_DWORD /d 0xFF /f
Disable AutoPlay:
# Per user, AutoPlay setting
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers" -Name "DisableAutoplay" -Type DWord -Value 1
Disable Automount
diskpart.exe; automount disable;
# or
mountvol /N
# or
reg add HKLM\SYSTEM\CurrentControlSet\Services\MountMgr /v NoAutoMount /t REG_DWORD /d 1 /f
Linux (xfce)
Mentioned in the earlier section on AutoRun.INF, by default, xfce does not auto-mount or auto-run any media. xfce: Managing Removable Drives and Media describes this behavior. Even if you allow this, it appears to still prompt you for confirmation when an app tries to launch.
Linux (KDE)
The KDE: Removable Devices docs don't appear to have any details on an AutoRun/Open/Exec feature.
Linux (GNOME)
See this example guide and dconf lockdown explaination.
- Create the following user profile:
/etc/dconf/profile/user
user-db:user
system-db:site
dconf Database Names
"site" is the name of the system database.
- For each database other than
useryou listed in the profile, create/etc/dconf/db/<databse>.d/if it doesn't already exist
sudo mkdir /etc/dconf/db/site.d
- Set the keys within a keyfile within the
localdatabase directory:
sudo nano /etc/dconf/db/local.d/00_media-handling:
[org/gnome/desktop/media-handling]
automount=false
automount-open=false
autorun-never=true
sudo mkdir /etc/dconf/db/local.d/locks
sudo nano /etc/dconf/db/local.d/locks/media-handling:
/org/gnome/desktop/media-handling/automount
/org/gnome/desktop/media-handling/automount-open
/org/gnome/desktop/media-handling/autorun-never
- Update the database
sudo dconf update
-
Users must logout and back in for the system-wide settings to take effect.
-
Confirm by trying to change a locked key. You should receive the following output:
gsettings set org.gnome.desktop.media-handling automount true
"The key is not writable"
Filesystem Protections
What this means is any process or executable spawning from a mounted or removable share or drive is suspicious, and should generally be outright blocked.
Windows (Filesystem ASR Rules)
On Windows, you'll want to enable the attack surface reduction (ASR) rule to block untrusted and unsigned processes that run from USB, or your security platform's equivalent.
Linux (Filesystem Capabilities)
On Linux, you can configure partitions (including mount points) to not execute binaries via the noexec directive in /etc/fstab. You should also configure nodev and nosuid on these paths as well, but they're often the default.
The Ubuntu 22.04 CIS L2 Server Guide: noexec on /dev/shm has Ansible and Bash snippets, ready-to-use, that show you how to do this. You're adding the noexec flag to partitions under /etc/fstab.
To test this, you can copy an existing binary out of the OS path:
# Copy the id bin to /dev/shm
cp /usr/bin/id /dev/shm/
# Execute it to confirm you can
/dev/shm/id
uid=1000(user1) gid=1000(user1) groups=1000(user1),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd)
Now if you were to copy the remediation script block above into a noexec.sh and run it, you'll see binaries no longer execute on that path:
# Create the remediation script from https://static.open-scap.org/ssg-guides/ssg-ubuntu2204-guide-cis_level2_server.html#xccdf_org.ssgproject.content_rule_mount_option_dev_shm_noexec
nano ./noexec.sh
sudo bash ./noexec.sh
# Confirm id no longer executes
/dev/shm/id
-bash: /dev/shm/id: Permission denied
Limitations
This does NOT prevent script execution (.py, .sh, .rb, .ps1), if they're executed via the relevant binaries already installed within the OS (e.g. /usr/bin/*).
Here's a test you can do to confirm this, write a small python script that writes "pwned" to terminal, following up from our id test earlier:
# This does not work
chmod +x /dev/shm/test.py
/dev/shm/test.py
-bash: /dev/shm/test.py: Permission denied
# This does work
python3 /dev/shm/test.py
pwned
# Binary files are still blocked, even when using a system binary to run them
bash /dev/shm/id
/dev/shm/id: /dev/shm/id: cannot execute binary file
See Securing Debian: Chapter 04, Section 10 for more on setting noexec nodev and nosuid on filesystem partitians.
cat /proc/mounts or mount -l will show the filesystem and device capabilities:
tmpfs on /run type tmpfs (rw,nosuid,nodev,noexec,relatime[...]
Notable syscalls for auditd rules:
execve,execl,execlp,execle,execv,execvp,execvpe: Execute a file (all front-ends for execve, syscall 59)fork: Process fork/cloneclone: Process fork/cloneptrace: Process injectionopenat: Open or create a fileconnect: Connection, can be local or remote
Monitor your Mount Path
Mount paths like /media are defined either as a default, or by the user. You could mount an external filesystem anywhere. Because of this, you need to take one of two things into account:
- Either have dynamic auditing rules that will catch all process creation (you can filter based on path then)
- Only permit mounting to specific paths, that have unique auditing rules watching them for process creation
Example auditd policy for detection:
# /etc/audit/rules.d/40-usb.rules
-a always,exit -F arch=b32 -F dir=/media/ -S socketcall -F key=T1091.1_Replication_Through_Removable_Media
-a always,exit -F arch=b64 -F dir=/media/ -S connect -F key=T1091.1_Replication_Through_Removable_Media
-a always,exit -F arch=b32 -F dir=/media/ -S open -F key=T1091.2_Replication_Through_Removable_Media
-a always,exit -F arch=b64 -F dir=/media/ -S openat -F key=T1091.2_Replication_Through_Removable_Media
-a always,exit -F arch=b32 -F dir=/media/ -S clone -S fork -F key=T1091.3_Replication_Through_Removable_Media
-a always,exit -F arch=b64 -F dir=/media/ -S clone -S fork -F key=T1091.3_Replication_Through_Removable_Media
-a always,exit -F arch=b32 -F dir=/media/ -S execve -F key=T1091.4_Replication_Through_Removable_Media
-a always,exit -F arch=b64 -F dir=/media/ -S execve -F key=T1091.4_Replication_Through_Removable_Media
Relevant excerpts from the exec, execve, capabilities, and mount man pages:
execve
execve(2)
execve() executes the program referred to by pathname. This causes the program that is currently being run by the calling process to be replaced with a new program, with newly initialized stack, heap, and (initialized and uninitialized) data segments.
capabilities
capabilities(7)
If a thread drops a capability from its permitted set, it can never reacquire that capability (unless it execve(2)s either a set-user-ID-root program, or a program whose associated file capabilities grant that capability).
exec
exec(3)
p - execlp(), execvp(), execvpe()
These functions duplicate the actions of the shell in searching for an executable file if the specified filename does not contain a slash (/) character. The file is sought in the colon-separated list of directory pathnames specified in the PATH environment variable. If this variable isn't defined, the path list defaults to a list that includes the directories returned by confstr(_CS_PATH) (which typically returns the value "/bin:/usr/bin") and possibly also the current working directory; see NOTES for further details.
If the specified filename includes a slash character, then PATH is ignored, and the file at the specified pathname is executed.
In addition, certain errors are treated specially.
If permission is denied for a file (the attempted execve(2) failed with the error EACCES), these functions will continue searching the rest of the search path. If no other file is found, however, they will return with errno set to EACCES.
If the header of a file isn't recognized (the attempted execve(2) failed with the error ENOEXEC), these functions will execute the shell (/bin/sh) with the path of the file as its first argument. (If this attempt fails, no further searching is done.)
All other exec() functions (which do not include 'p' in the suffix) take as their first argument a (relative or absolute) pathname that identifies the program to be executed.
mount
mount(8)
noexec Do not permit direct execution of any binaries on the mounted filesystem.
Physical & Firmware Security
These suggestions fall slightly outside of USB itself, but consider attacks that can be done with physical access and a USB.
Set a Firmware / Boot / UEFI Password
Requiring this password during administrative UEFI actions / boot sequences can prevent adversaries with physical access from booting via unauthorized live USB's. Kali Linux for example could be run from a USB and used to mount the drives, modify data on unencrypted boot partitions, modify the device firmware, and more.
Enforce Secure Boot
If combined with a firmware password, and other low-tech physical security techniques that can help you detect chassis intrusion, you can have a reasonable level of confidence in your boot chain integrity if the CMOS and TPM values have not been cleared and your Secure Boot signatures have not changed.