Rescue Your Amazon Dash Buttons

Earlier this year, Amazon announced that they’ll discontinue Dash Buttons. I don’t know how successful Dash Buttons were for their intended use, but Home Automation hackers have loved (mis-)using them for everything from warming up their coffee pot to keeping track of bodily functions.

Unfortunately for us hackers, Amazon is an unforgiving god. Not only have they stopped selling Dash Buttons, but they’ve removed the part of their app used to set new ones up. Even worse, to any button unfortunate enough to connect to The Mothership, Amazon has promised to issue a firmware update that bricks the device. It is therefore critical that you set up your buttons in an environment where they will not be able to phone home.

Fortunately for us hackers, Amazon is not an infallible god. Versions of their dash button firmware built on May 2016 and earlier are vulnerable to a buffer overflow attack during the high-frequency audio setup (Hunz did some truly awesome reverse engineering work to find this).

We can exploit this vulnerability to complete the setup.

How-To

In the following section, I’ll go into more detail about how this works.

For now, let’s do this!

  1. Put Dash Button in setup mode by holding down the button until the LED flashes blue.
    1. Connect to the Amazon ConfigureMe WiFi network and visit http://192.168.0.1.
    2. You’ll see the button’s hardware (MAC) address. Block its Internet access in your router’s settings. If you don’t do this, the button will get an over-the-air update when it phones home and get bricked.
  2. While in setup mode, play this .wav file through some earbuds aimed at the Dash Button.
    • If the LED turns green, the exploit worked! Carry on to step (3).
    • If the LED turns off, you’re probably on a firmware version that fixed the vulnerability. Unfortunately, you’re out of luck if this is the case. (unless someone finds another vulnerability)
  3. Put the Button in setup mode again.
  4. Connect to the WiFi network it creates — Amazon ConfigureMe.
  5. Visit this URL*: http://192.168.0.1/?amzn_ssid=<wifi_network_name>&amzn_pw=<wifi_network_pw>. (obviously substituting wifi_network_name and wifi_network_pw for the desired values)

That’s it! It should work now.

[ * ]: Note that the setup AP is unsecured and this request is sent over HTTP. You’re sending this request in plaintext over the air. Don’t do this unless you’re comfortable with that. The buttons support a configuration flow that involves exchanging crypto keys, but this is far more involved. If there’s enough interest, I can write a script.

How this works

The Dash Button setup process has two high-level steps:

  1. Getting WiFi credentials from you.
  2. Exchanging a pair of secrets with The Mothership. Under normal operation, these are used to authenticate with Amazon when placing an order (it uses them to generate an HMAC secret).
    1. The button transfers a device secret baked into the firmware to Bezos HQ.
    2. The button retrieves and stores a customer secret from Amazon.

(1) is easy for us to fake. In fact, all we need is the final step from the previous section — visiting the URL with the amzn_ssid and amzn_pw parameters.

It’s (2) that’s keeping everyone from setting up their buttons. Amazon has stopped responding to these exchange requests, meaning the buttons will never complete the setup process unless we get creative.

The part of the firmware that handles high-frequency audio packets is vulnerable to a buffer overflow attack. From Hunz’s slides, you can see that it’s doing a memcpy without a length check:

Hunz put together some excellent scripts that pack an exploit payload in ARM assembly into an audio file.

I needed to do some reverse engineering of my own to find the function responsible for writing the customer secret to flash. I’d never so much as opened a disassembler, so this was a pretty fun challenge. Since IDA costs an arm, a leg, and the souls of any present and future offspring, I used Ghidra (I have no complaints, although a professional might). I put the archive file on Github.

The raw function that writes a customer secret to flash is at address 0x40FAA4:

It takes in a pointer and a length (which appears to always be 20). This function is normally wrapped in a bunch of code that calls Amazon’s servers, does validation, etc., but since we’ve got arbitrary code execution, we can just call it directly.

My exploit payload follows:

Since it doesn’t matter what the value of this secret is so long as we’re not intending to connect to Amazon, I pass an arbitrary address (0x400000 — the start of ROM) along with a length of 20 to the writeCustomerSecret function.

Then it sets the LED to green to indicate success. Firmware versions that have patched this vulnerability shut down when they receive the exploit.

Further fun

When starting on this effort, I soldered some magnet wire onto the UART test pads to get serial access. Hunz labels the pins in his talk:

Here’s a photo of my test rig:

The most interesting thing you can do with UART access is execute more code. The audio exploit payload is limited to a small number of instructions. Hunz supplied a payload that reads data from UART into SRAM and executes it (there may be a more convenient way to do this, but I’ve not dug in yet). Soldering onto these tiny pads is pretty challenging, so I modeled and 3D-printed a crude pogo pin fixture:

Pogo pin fixture. Connects to UART RX/TX pins. Gnd is connected separately.

I’d initially thought this was necessary in order to configure wifi credentials, but turns out you can do that using the setup AP, which is much easier.

You can’t do much of anything interesting in the serial console, but it at least appears that someone over at Amazon has a sense of humor:

Acknowledgements

  • Hunz’s reverse engineering work is incredible. If you’re into this sort of stuff at all (and if you’re reading this, you probably are), you’d very likely get a huge kick out of his 33c3 talk, which is where I learned about the audio vulnerability.

Future Work

The Dash Button hardware is pretty remarkable. It’s got a beefy microcontroller, (obviously) builtin wifi, a BLE chip, a microphone for the HFA audio configuration, and so on. I’ve not seen any official-looking estimates at the cost Amazon was paying for these things, but some have guessed in the ballpark of $20 — even at Amazon’s scale.

If we can find a way to flash custom firmware, they’d be perfect IoT buttons. As-is, they’re obviously a little janky. We’re monitoring networks for side-effects to trigger actions. This should theoretically be possible given that Amazon issues OTA firmware updates (the code that handles the OTA update process appears to be at 0x42391C).

I don’t know how much gas is left in my motivation-for-reading-assembly tank, but this is what I’d work on next with what’s left.

It’d be really neat if Amazon open-sourced an SDK. Yes, they’ve said they have a recycling program, but something tells me most buttons are gonna end up in the landfill.

Caveats

  1. Amazon fixed the buffer overflow vulnerability in a later version of the firmware, but almost every button I have uses the May 2016 version out of the box (there’s been ~1/20 exceptions).
  2. Buttons get OTA updates if they connect to the Internet. So if you have a button that’s been phoning home, in all likelihood it’s been patched.
  3. My setup triggers on 802.11 probe requests, meaning I don’t need (or want) the button to connect to a network, only to try. As far as I can tell, though, they will.

Donating

If this work has brought you happiness or utility, it’s more than enough for me to hear those words.

If you’re feeling especially generous, and are open to a charitable donation, that’d make me very happy. Here are some whose mission I support (in no particular order):

Webpack with Arduino and PlatformIO

Web development for embedded devices sucks. More often than not, it involves editing concatenated strings in a header file. Even some of the most popular web projects like Tasmota, WiFiManager, and esphome work like this.

If you’ve done any web development recently, it’s probably involved build tooling like Webpack. This makes it super easy to include external libraries, and to pack all of your assets (javascript, images, stylesheets) into an easy-to-distribute bundle. There’s also a wealth of incredible development tools like hot reloading, and support for alternative languages like Typescript.

Why is the experience so different when developing web applications for embedded devices?

To serve assets, you have these options:

  1. Embed the assets in the source code. This is a pain in the butt, but is a very straightforward approach and results in a complete firmware image.
  2. Side-load assets on, e.g., SPIFFS. This introduces an out-of-band step to get your project running.
  3. Serve assets from an external source. This introduces a point of failure, and requires Internet access.

(2) and (3) make for a much nicer development experience, but make for a crappy user experience. (1) is the reverse. It makes sense that developers optimize for their users.

There’s good news: we can have our cake and eat it. It just requires some simple build tooling. We can use Webpack as we normally would, have it generate a messy header file that our compiler will happily pack into a firmware image for us.

Example

I put together a skeleton example on Github, available here:

https://github.com/sidoh/webpack_with_platformio

Hopefully this serves as a useful quickstart, but I’ll give a more detailed overview below.

Moving Pieces

There are three high-level parts:

  1. The main PlatformIO application (./platformio.ini, ./lib, ./src).
  2. The web app (./web)
  3. A Webpack plugin to cram the web assets into a header file and a PlatformIO build script to call it (./.build_web.py)

./web is a self-contained Webpack application. We can iterate on it using the standard builtin development server. When we’re done, we can call the standard pio run --target upload to run the PlatformIO build. It’ll rebuild the web assets, pack them into a header file, and recompile our application.

The webserver is configured to dynamically serve the assets from the header file.

Result

Now that the build process is set up, we can focus on writing a great web app. Here’s an example of something I built for one of my projects, epaper_templates (I’ll talk about the new version in a future post at some point).

epaper_templates bitmap editor

This is a simple bitmap editor with local image importing, undo/redo stack, resizing, etc. Writing this in raw Javascript would be a giant pain in the butt. Doing it with React and the full richness of the Javascript developer community was an absolute delight. It took me a couple of evenings.

Continuous Integration

It’s pretty straightforward to get a build tool like TravisCI to build and distribute pre-compiled firmware images, complete with web assets. My epaper_templates project does this for tagged releases. Its .travis.yml may serve as a useful reference.

Downsides

This is, of course, not entirely free. Let’s discuss some of the costs:

  1. We’re embedding all of our assets in source. We’re obviously using progmem, but we still only have a couple of MBs of flash to play with. The above example is around 500 KB when it’s said and done.
  2. It’s is clearly more work than just putting stuff in header strings. If what you’re trying to do is simple, this is probably not the right approach for you.
  3. It adds dependencies to your build (e.g., node, npm).

Conclusion

When we have powerful tools, we can build really cool stuff without too much effort. Hopefully this is a useful reference for anyone wanting to use modern web development tooling in their embedded projects.

Ready-Made MiLight Hub

h4nc over at the HomeAssistant community forums has put together a spectacular ready-made hardware set for my ESP8266 MiLight Hub software. This includes a PCB and a 3D-printed case.

These look super snazzy, and will remove a lot of the guesswork from the setup process (skip the jumper wire fiddling and head-scratching when you read the pinout wrong!)

Awesome job, h4nc!

h4nc is offering ready-made kits which include:

  • A NodeMCU pre-flashed with the latest version of ESP8266 MiLight Hub
  • An nRF24 module with antenna
  • 3D-printed case

To order one for yourself, please get in touch with him at h4nc.zigbee(a)gmail.com, or drop him a PM on the HomeAssistant community forum.

You can see (and leave) feedback on h4nc’s readymade kits on the aforementioned HomeAssistant forum post.

Open Source

h4nc graciously open-sourced his work. You can find the Gerber files on Github, and the 3D-printable STLs on Thingiverse.

If you do end up making one of these for yourself, please consider a donation to h4nc. Contact him at h4nc.zigbee(a)gmail.com.

Links