Building IoT: A Hacker’s Journey
May 02, 2017
Being a first time home owner means a lot of different things, but in particular I’ve found it means fixing a lot of things. A garage door opener has been on my fix-it list for a while and I finally got around to solving it! This blog post will cover the IoT device I created and the security protections I baked in along the way!
Backstory and Motivation
Shortly after moving into my new home, I found a key switch (on the right) near the front of my garage. I tested all the keys I was given and none of them worked. At the time, I had lots of bigger projects to work on, so I left it at that. Eventually, I got around to taking a closer look and I traced the key switch’s wires to the inside button that open and closed my garage. Hmmmm. I quickly cut and striped the wires near the key switch and found that if I touched them together, my garage would open! I did not like this! Anyone with a pair of vise grips, or better yet a dremel, could remove the “security bolts”, unmount the switch from the outside, cut the wires, and touch them to get into my garage. Even if I replaced the key switch with a keypad, or retina scanner for that matter, it would still be vulnerable to the previously outlined attack if it was using those 2 wires. I needed to somehow make the wiring that an attacker could access be independent from the logic to open the garage or not.
I had two ideas. The first idea was to use a microcontroller and a keypad. The keypad would simply communicate number key presses to the microcontroller, which would chose to open the garage or not. This way if an attacker gained access to the wires, there would be nothing they could short to open the garage. Well, that’s not technically true, because they could short the correct button wires in the correct order to open the garage, but you get the point. The second idea was to use a microcontroller running a web server that I could connect to using my phone to open the garage. The beauty here is that there are no wires exposed for an attacker, however, there are other things to consider. For example, the security and access of my garage via this channel hinges on the availability and security of the web server on the microcontroller. I ultimately decided to build the later because it’s way cooler to open my garage from my phone and it would be a good exercise at attempting to build and secure an IoT device.
The Electronics
I decided to use a RaspberryPi Zero W. It’s a cheap device (~$10) that boasts 17 GPIO pins, runs full Linux, and has built-in wireless. Before devising a circuit, I had to figure out what the two garage wires were doing. I grabbed my multimeter and found through various tests that one wire supplied 5 volts DC (let’s call it power) and the other opened the garage when supplied the 5 volts (let’s call it input). I had a few options. I could pull the input wire high (meaning give it 5 volts) using the RaspberryPi, but I didn’t know if this would work given the RaspberryPi and garage don’t share a ground. I could use a transistor, but again I didn’t know if it would work given the common ground issue. Additionally, both of those ideas don’t protect the RaspberryPi from the garage, or vise versa, in case of overload or other failures. I ultimately went with a relay, which is a device that uses an electromagnet to mechanically operate a switch. This would provide complete isolation between the RaspberryPi and garage, while removing the potential for any ground related issues.
Lastly, I have a two car garage with two single garage doors, so I will need a circuit for both if I want to control both. With those considerations, here is a schematic and parts list of the final system:
Note: The relays are simply connected to the same 2 wires used by inside button. Effectively emulating a button press.
- Raspberry Pi Zero W
- Tolako 5v Relay (2)
- Jumper Ribbon Wires Cables M/F
- Electrical Junction Box (much cheaper than electronic project boxes.)
- Misc. M3 hardware
The Software and Security
When developing the software, I wanted to challenge myself as if I was developing an IoT device for market. I wanted to consider things like ease of use, size, embedded resource limitations, cost, and etc. as if it was a real IoT device.
I had no real hardware experience prior to this project, so I spent lots of time experimenting at the command line with GPIO things to get an understanding of what I wanted my code to do. The most useful tool I found was called gpio. I used it to read and write the state of my pins, as well as change the modes. This allowed me to test and play with my relays relatively quickly. Below are examples of the commands I used most:
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 |
### gpio readall - shows the state/mode of all pins. as well as their descriptions and gpio/pi/physical numbering. pi@raspberrypizero:~ $ gpio readall +-----+-----+---------+------+---+-Pi ZeroW-+---+------+---------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+ | | | 3.3v | | | 1 || 2 | | | 5v | | | | 2 | 8 | SDA.1 | IN | 1 | 3 || 4 | | | 5v | | | | 3 | 9 | SCL.1 | IN | 1 | 5 || 6 | | | 0v | | | | 4 | 7 | GPIO. 7 | IN | 1 | 7 || 8 | 0 | IN | TxD | 15 | 14 | | | | 0v | | | 9 || 10 | 1 | IN | RxD | 16 | 15 | | 17 | 0 | GPIO. 0 | IN | 0 | 11 || 12 | 0 | IN | GPIO. 1 | 1 | 18 | | 27 | 2 | GPIO. 2 | IN | 0 | 13 || 14 | | | 0v | | | | 22 | 3 | GPIO. 3 | IN | 0 | 15 || 16 | 0 | IN | GPIO. 4 | 4 | 23 | | | | 3.3v | | | 17 || 18 | 0 | IN | GPIO. 5 | 5 | 24 | | 10 | 12 | MOSI | IN | 0 | 19 || 20 | | | 0v | | | | 9 | 13 | MISO | IN | 0 | 21 || 22 | 0 | IN | GPIO. 6 | 6 | 25 | | 11 | 14 | SCLK | IN | 0 | 23 || 24 | 1 | IN | CE0 | 10 | 8 | | | | 0v | | | 25 || 26 | 1 | IN | CE1 | 11 | 7 | | 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 | | 5 | 21 | GPIO.21 | OUT | 0 | 29 || 30 | | | 0v | | | | 6 | 22 | GPIO.22 | OUT | 0 | 31 || 32 | 0 | IN | GPIO.26 | 26 | 12 | | 13 | 23 | GPIO.23 | IN | 0 | 33 || 34 | | | 0v | | | | 19 | 24 | GPIO.24 | IN | 0 | 35 || 36 | 0 | IN | GPIO.27 | 27 | 16 | | 26 | 25 | GPIO.25 | IN | 0 | 37 || 38 | 0 | IN | GPIO.28 | 28 | 20 | | | | 0v | | | 39 || 40 | 0 | IN | GPIO.29 | 29 | 21 | +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+---------+------+---+-Pi ZeroW-+---+------+---------+-----+-----+ ### gpio mode - change the mode of a pin (21) to IN or OUT pi@raspberrypizero:~ $ gpio mode 21 IN pi@raspberrypizero:~ $ gpio mode 21 OUT ### gpio write- set a pin (21) to High (1) or to Low (0) pi@raspberrypizero:~ $ gpio write 21 1 pi@raspberrypizero:~ $ gpio write 21 0 |
After building a decent understand of GPIO and learning how to interact with them using the gpio tool, it was time to bust out some Python. There is a GPIO Python library called gpiozero that contained all the GPIO functionality needed to switch my relays. Here is the snippet of my code that defines and initializes my pins using gpiozero:
1 2 3 4 5 |
#GPIO Setup leftGarage = gpiozero.DigitalOutputDevice(5) rightGarage = gpiozero.DigitalOutputDevice(6) rightGarage.off() leftGarage.off() |
From here I can pull the pins high or low, which in my case opens or closes the relay, as so:
1 2 |
rightGarage.on() rightGarage.off() |
That takes care of all my GPIO interactions, now all I had to do was build a UI and secure it. As usual, a simple web application is the easiest and fastest UI. Even though I only intended to host it on my internal LAN, I still didn’t want to leave it wide-open for anyone to use. I didn’t necessarily want to mess with users and sessions, as that increases the difficulty of development while decreasing the device’s ease of use. Logging into a web application is the last thing I would want to do when grabbing a moped from the garage or etc. Additionally, no IoT manufacturer would want this either. I decided to use client certificates, which is a type of digital certificate that is used by client systems to make authenticated requests to a remote server (Thanks Wikipedia). This would add robust authentication, without having the hassle of usernames and passwords. Using client certificates, I would simply install the certificate on devices I want to have access, while everything else will get denied. I was able to find a really awesome thread on Reddit that described how to use client certificates in Flask, a web-framework for Python. It’s as simple as building an “SSLContext” and then starting the app object with it, as seen below:
1 2 3 4 5 6 7 8 9 10 11 12 |
#TLS Setup CERT_FILE = '{mycert}.cert' KEY_FILE = '{mykey}.key' ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) ssl_ctx.load_cert_chain(CERT_FILE, KEY_FILE) ssl_ctx.verify_mode = ssl.CERT_REQUIRED ssl_ctx.load_verify_locations(cafile=CERT_FILE) [...other flask server stuff...] #Runs App app.run('192.168.0.150', 443, app, ssl_context=ssl_ctx) |
I generated my keys using openssl like so:
1 2 3 4 |
pi@raspberrypizero:~/ $ openssl genrsa 1024 > mykey.key pi@raspberrypizero:~/ $ openssl req -new -x509 -nodes -sha1 -days 365 -key mykey.key > mycert.cert pi@raspberrypizero:~/ $ cat mykey.key mycert.cert > example.pem pi@raspberrypizero:~/ $ openssl pkcs12 -export -in example.pem -out example.p12 -name "example" |
To setup a device to use the web application, all I had to do was install the “example.p12” certificate into the browser. On Android, I went to “Settings > Security > Install from storage” and then selected “example.p12”. Now when I visit my web application, it asks me what certificate to authenticate with:
Now with my authentication sorted out, the last thing I wanted to do was mitigate CSRF. If I was a real IoT manufacturer and my devices were in lots of people’s homes, it would be pretty bad if you could get a user’s garage to open just by having that user click a malicious link or visit a hacked site. While Flask doesn’t mitigate CSRF out-of-the-box, WTForms does and there is a Python module to integrate Flask and WTForms, rightfully called Flask WTF. Using WTForms with CSRF enabled, I can create a POST form that ultimately controls my garage and won’t be vulnerable to CSRF. In order for CSRF nonce tokens to be generated, the Flask app object needs to have a secret set. Here are my codes snippets pertaining to setting the secret, creating a WTForm, and building an HTML page to render:
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 |
#Flask Setup app = Flask(__name__) app.secret_key = 's3cr3t' #changeme #Form Setup class MyForm(FlaskForm): whichGarage = RadioField('Which garage?', choices=[('leftGarage','Left'),('rightGarage','Right')], validators=[DataRequired()]) #Main Page Setup @app.route('/',methods=['GET']) def index(): return render_template_string(""" <html> <head><title>Open Sesame 3000</title></head> <body style="background-color:Black;color:Lime;"> <form method="POST" action="/garage"> {{ form.csrf_token }} {{ form.whichGarage.label }} </br> {% for subfield in form.whichGarage %} <table><td> <tr> {{ subfield }} </tr> <tr> {{ subfield.label }} </tr> </td></table> {% endfor %} <input type="submit" value="Open!"> </form> </body> </html> """,form=MyForm()) #Garage Page Setup @app.route('/garage',methods=['POST']) def led(): ledz = request.form.get('whichLed') if ledz == "rightGarage": print "opening right" rightGarage.blink(0.05,0.05,2) elif ledz == "leftGarage": print "opening left" leftGarage.blink(0.05,0.05,2) return redirect(url_for('index')) |
At the bottom of the above snippet you can see the page the form POSTs to, which ultimately controls the GPIO relays. If you notice, I’m using the blink() method. I originally just used on() and off(), but later after RTFM’ing on my garage, I found out I needed to pulse the relay twice in order to trigger the garage. The blink() method makes that easy. The flow of the web application is this: A user first lands on the index (“/”) page which has a simple form with a 2 radio buttons to specify which garage to open. After selecting a garage and hitting a “Open” submit button, a POST is made to “/garage”, which triggers the GPIOs and redirects back to the index page. And thats it! Pretty simple. The last step in any UI design, which is arguably the most important step, is to spice it up a bit with some ASCII art:
Note: I’m using a self-signed certificate, so my mobile browser doesn’t trust it, hence the red in the URL.
And there it is! Here’s a link to the source code on GitHub. All that is left is to put it all together in some sort of case and mount in my garage. Here are some photos of that process:
Like I mentioned before, this was my first hardware project, so I had lots of new experiences and fun building this. I’m pretty proud of this device and have been using it like crazy so far. An interesting scenario I never considered until finishing the project revolved around the boot-up state of GPIO pins. If, for whatever reason, the relays pulsed while the RaspberryPi was booting (prior to my server script running), my garage could potentially open. I tested the theory a few times by pulling the power and plugging it back in. Neither garages opened, so I was relieved. I’m always amazed with the power of Python. I was able to build this entire project (web server, client certificate authentication, CSRF protections, GPIO interactions, and all) in just about 100 lines of code, of which 28 lines were ASCII art. 🙂
Here is a video of it in action!
I enjoyed messing around with some hardware for a change!
Thanks for reading!