Preventing USB Attacks with Grsecurity
An update to this post using the linux-hardened
project is available here.
USB has some surprising security implications: when a device is plugged in, the operating system generally loads the appropriate driver and initializes it. For example, plugging a device into an unlocked computer can execute code, since the device can act as a USB keyboard. This is how the "BadUSB" series of attacks work.
Samy Kamkar's Poisontap project has been getting a lot of press recently. It's a little more interesting since it can work on locked computers.
When PoisonTap (Raspberry Pi Zero & Node.js) is plugged into a locked/password protected computer, it:
- emulates an Ethernet device over USB (or Thunderbolt)
- hijacks all Internet traffic from the machine (despite being a low priority/unknown network interface)
- siphons and stores HTTP cookies and sessions from the web browser for the Alexa top 1,000,000 websites
- exposes the internal router to the attacker, making it accessible remotely via outbound WebSocket and DNS rebinding (thanks Matt Austin for rebinding idea!)
- installs a persistent web-based backdoor in HTTP cache for hundreds of thousands of domains and common Javascript CDN URLs, all with access to the user's cookies via cache poisoning
- allows attacker to remotely force the user to make HTTP requests and proxy back responses (GET & POSTs) with the user's cookies on any backdoored domain
- does not require the machine to be unlocked
- backdoors and remote access persist even after device is removed and attacker sashays away
grsecurity comes with a mitigation. If your grsecurity kernel is built
with GRKERNSEC_DENYUSB
, then the kernel.grsecurity.deny_new_usb
sysctl lets you prevent new USB devices from being loaded:
grsecurity-3.1-4.8.14-201612110933.patch:121501
a new sysctl option with name "deny_new_usb" will be created. Setting its value to 1 will prevent any new USB devices from being recognized by the OS. Any attempted USB device insertion will be logged. This option is intended to be used against custom USB devices designed to exploit vulnerabilities in various USB device drivers.
For greatest effectiveness, this sysctl should be set after any relevant init scripts. This option is safe to enable in distros as each user can choose whether or not to toggle the sysctl.
I wrote a systemd service so that I can enable it on boot and suspend,
and sudo systemctl stop deny_new_usb
when I actually want to use a
USB device.
[Service] Type=oneshot ExecStart=/usr/bin/sysctl kernel.grsecurity.deny_new_usb=1 ExecStop=/usr/bin/sysctl kernel.grsecurity.deny_new_usb=0 RemainAfterExit=yes [Install] WantedBy=default.target suspend.target sleep.target
and added a bit to i3status
, so that I can see whether it's on or
not in my statusbar:
#!/bin/bash set -e i3status | while true; do read line if systemctl status deny_new_usb >/dev/null then usb_status="USB 🔒" else usb_status="USB 🔓" fi echo "$usb_status | $line" done