-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path2021-01-11-usbkiller.html
197 lines (145 loc) · 9.55 KB
/
2021-01-11-usbkiller.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width,initial-scale=1" name="viewport">
<link rel="preload" as="font" href="/static/fonts/InterVariable.woff2" crossorigin="" type="font/woff2">
<link href="/style.css" rel="stylesheet" type="text/css">
<link href="/static/fonts/inter.css" rel="stylesheet" type="text/css">
<link href="/rss.xml" rel="alternate" type="application/rss+xml">
<title>Usbkill the OpenBSD Way</title>
</head>
<body>
<header>
<nav>
<p>
<a href="/" class="index">zakaria.org</a> <a href="/posts">Blog</a> <a href="/projects.html">Projects</a> <a href="/about.html">About</a>
</p>
</nav>
</header>
<main>
<p><small>2021-01-11</small></p>
<h1 id="usbkill-the-openbsd-way"><code>usbkill</code> the OpenBSD way</h1>
<p><a href="https://github.com/hephaest0s/usbkill"><code>usbkill</code></a> is a kill-switch that shuts down your computer on any USB change. It does this by watching the output of <code>lsusb</code> and when there is a change it runs <code>shutdown -h now</code>.</p>
<p>Simple, right? One thing to note is that <code>lsusb</code> is not included in OpenBSD’s base packages, but <a href="https://man.openbsd.org/hotplugd"><code>hotplugd(8)</code></a> is.</p>
<h2 id="hotplugd">hotplugd</h2>
<p>So what is <code>hotplugd</code>, and how can it be useful? The <a href="https://man.openbsd.org/hotplugd">man page</a> does a good job of explaining it. Simply put: when any device is attached to or detached from your machine <code>hotplugd</code> will execute a script.</p>
<p>To see how simple it is to write a hotplug script we can start by simply logging device attach events. First, start by enabling and starting <code>hotplugd</code> (as root):</p>
<pre><code># rcctl enable hotplugd
# rcctl start hotplugd
hotplugd(ok)
</code></pre>
<p>Next we will write the script that is executed on a device attach event:</p>
<pre><code># mkdir -p /etc/hotplug
# $EDITOR /etc/hotplug/attach
</code></pre>
<p>In this file we will log the device class and name:</p>
<pre><code>#!/bin/sh
DEVCLASS=$1
DEVNAME=$2
# log attach event
logger -t hotplug "$DEVCLASS:$DEVNAME attached"
</code></pre>
<p>To see this in action in another terminal type</p>
<pre><code>$ tail -f /var/log/messages
</code></pre>
<p>Then connect a USB device to your machine and you should see messages tagged ‘hotplug’. This is what I get when I plug in my Logitech USB adapter for my wireless mouse (which I usually don’t use):</p>
<pre><code>Jan 11 11:48:32 x1 hotplug: 0:uhid3 attached
Jan 11 11:48:32 x1 hotplug: 5:wsmouse2 attached
Jan 11 11:48:32 x1 hotplug: 0:ums0 attached
Jan 11 11:48:32 x1 hotplug: 0:uhid1 attached
Jan 11 11:48:32 x1 hotplug: 5:wskbd1 attached
Jan 11 11:48:32 x1 hotplug: 0:uhid0 attached
Jan 11 11:48:32 x1 hotplug: 0:uhid4 attached
Jan 11 11:48:32 x1 hotplug: 0:uhid2 attached
Jan 11 11:48:32 x1 hotplug: 0:uhidev1 attached
Jan 11 11:48:32 x1 hotplug: 0:uhidev2 attached
Jan 11 11:48:32 x1 hotplug: 0:ukbd0 attached
Jan 11 11:48:32 x1 hotplug: 0:uhidev0 attached
Jan 11 11:48:32 x1 hotplug: 0:uhid5 attached
Jan 11 11:48:32 x1 hotplug: 0:uhid6 attached
</code></pre>
<p>Site note: What is happening here? Why have so many events popped up after inserting one USB device? My theory is that because it’s a <a href="https://www.logitech.com/product/unifying-receiver-usb">Unifying Receiver</a>, it allows more than one Logitech HID to be connected to a single receiver, so it must register a bunch of HIDs to the kernel.</p>
<h2 id="the-kill-part">The ‘kill’ part</h2>
<p>Now that we’ve seen how <code>hotplugd</code> works, we can work on the <em>kill</em> part of <code>usbkill</code>.<br>
We want to shutdown the machine on a device attach or detach event, but we also want to be able to arm and disarm the <em>kill</em> part, since I might need to plug something in once in a while. Make the <code>/etc/hotplug/attach</code> script as so:</p>
<pre><code>#!/bin/sh
arm_file=/tmp/arm_usbkill
DEVCLASS="$1"
DEVNAME="$2"
logger -t "${0##*/}" "${DEVCLASS}:${DEVNAME} attached"
if [ -f "$arm_file" ]; then
shutdown -p now
else
logger -t "${0##*/}" "unarmed - aborted shutdown"
fi
</code></pre>
<p>If the <code>/tmp/arm_usbkill</code> file exists then the machine will shutdown, if it doesn’t exist it will just add a log entry to syslog.</p>
<p><code>hotplug</code> also supports running a different script, <code>/etc/hotplug/detach</code> on detach events. Since both scripts are exactly the same I’ve symlinked the attach script to the location of the detach script.</p>
<pre><code># ln -s /etc/hotplug/attach /etc/hotplug/detach
</code></pre>
<p>The <code>${0##*/}</code> logger tag gets substituted to the filename of the script being executed (in this case it is either <code>attach</code> or <code>detach</code>).</p>
<p>One thing to note is that this setup will execute the shutdown command on <em>any</em> device change event. This includes USBs but also includes network devices, disk drives, and serial line interfaces<sup class="footnote-ref" id="fnref:1"><a href="#fn:1">1</a></sup>. If that is a problem, you can implement a device class-based whitelist by checking <code>$DEVCLASS</code>:</p>
<pre><code>#!/bin/sh
# class whitelist (space-separated)
class_whitelist="0 2 3 5"
# arm file
arm_file=/tmp/arm_usbkill
DEVCLASS="$1"
DEVNAME="$2"
whitelisted() {
for class in $class_whitelist; do
if [ "$class" = "$1" ]; then
return 0
fi
done
return 1
}
logger -t "${0##*/}" "${DEVCLASS}:${DEVNAME} attached"
if [ -f "$arm_file" ]; then
if whitelisted "$DEVCLASS"; then
logger -t "${0##*/}" "whitelisted - aborted shutdown"
exit 0
fi
shutdown -p now
else
logger -t "${0##*/}" "unarmed - aborted shutdown"
fi
</code></pre>
<p>But this is not really useful to me since I use a laptop and I’m not attaching and detaching network devices or disk drives.</p>
<p>One disadvantage of this setup is the inability to whitelist devices based on their USB IDs like you can with <code>usbkill</code>. This could be acheived through a much more complicated script using <code>usbdevs</code> to get USB IDs, but as of yet I have no need for that.</p>
<h2 id="arming-and-disarming">Arming and disarming</h2>
<p>To arm and disarm this script all you have to do is create or remove the <code>$arm_file</code> respectively. Here are some shell functions to add to your shell rc to make it easier:</p>
<pre><code># arm/disarm usbkill
arm() {
touch /tmp/arm_usbkill && printf 'armed\\n' || printf 'error arming\\n'
}
disarm() {
rm -f /tmp/arm_usbkill && printf 'disarmed\\n' || printf 'error disarming\\n'
}
</code></pre>
<p>The script can be armed or disarmed by any regular user which may or may not be preferable to you (and isn’t the case for <code>usbkill</code>, which requires root to run).<br>
Originally I had added the <code>uchg</code> flag to the file to lock it. But this proved to be counterproductive since it wasn’t cleared from <code>/tmp</code> on reboot and when <code>hotplugd</code> would first start up, it would immediately shutdown the machine again. That was fun to fix (not).</p>
<h2 id="why">Why?</h2>
<p>So why do all this? Why not just <code>pkg_add usbutils</code>, download + run <code>usbkill</code> and be done?<br>
Well for starters that isn’t as fun. The main reason is that all this works in a default OpenBSD install - no additional packages needed. Why install a program to solve a problem when the default tools and services can solve the problem just as (if not more) elegantly?</p>
<h2 id="see-also">SEE ALSO</h2>
<ul>
<li>OpenBSD <code>hotplug(4)</code> pseudo-device man page: <a href="https://man.openbsd.org/hotplug">https://man.openbsd.org/hotplug</a> .</li>
<li>OpenBSD includes the <code>usbdevs(8)</code> tool in base that lists connected USB devices and their IDs: <a href="https://man.openbsd.org/usbdevs">https://man.openbsd.org/usbdevs</a> <sup class="footnote-ref" id="fnref:2"><a href="#fn:2">2</a></sup>.</li>
<li>OpenWRT has it’s own similarly named hotplug.d service: <a href="https://openwrt.org/docs/guide-user/base-system/hotplug">https://openwrt.org/docs/guide-user/base-system/hotplug</a>. But it’s slightly different to OpenBSD’s.</li>
<li>A couple of years ago I wrote <a href="https://github.com/e-zk/hidlock">a hotplug script</a> that instead runs <a href="https://man.openbsd.org/xlock"><code>xlock(1)</code></a> on all running X displays after a HID is attached. In theory this would to thwart HID/badusb attacks, while not being as aggressive as shutting down your machine. Might be worth looking into if you like the sound of that.</li>
</ul>
<div class="footnotes">
<hr>
<ol>
<li id="fn:1">As per the <a href="https://man.openbsd.org/hotplugd"><code>hotplugd(8)</code> man page</a> <a class="footnote-return" href="#fnref:1"><sup>[return]</sup></a></li>
<li id="fn:2">In the future I might write a script to act more similarly to <code>usbkill</code>, using <code>usbdevs</code> to poll for device changes instead of <code>lsusb</code>. <a class="footnote-return" href="#fnref:2"><sup>[return]</sup></a></li>
</ol>
</div>
</main>
<footer>
<p><a href="https://creativecommons.org/licenses/by-sa/4.0/">© CC BY-SA 4.0</a> <a href="./2021-01-11-usbkiller.md">plaintext</a> <a href="http://64wv2uqwjacqer7z5d6ooqgrvjwlioizmo7hgmxm7zxerbvgnoqhafid.onion/posts/2021-01-11-usbkiller.html">onion</a></p>
</footer>
</body>
</html>