Dash Button Corral

August 2015 ยท 6 minute read

Amazon’s new Dash Button things are pretty cool. I bought a couple and wanted to keep the original firmware on them to not take them apart, but still control them and have them talk to my server rather than Amazon’s. So I set up my home router to be a “network of lies” to trick it into talking to my server as if it was an Amazon one. Here I’ll describe how you can do this too. For reference, my home router runs OpenWRT so this was all done with it. These changes might be possible with other Linux-based routers but I love OpenWRT and know it best so it’s what I used.

First thing is to set up your Button. Download the Amazon Shopping app on your iPhone or Android and set up the device as per the instructions. You can stop it at the last step to select a product if you want, or go ahead and select one if you want to use it as intended later. Just make sure the SSID you have them going to is your OpenWRT router that you control.

By running WireShark and ettercap, we can observe how the Dash Buttons behave. They phone home to “parker-gateway-na.amazon.com”. But they look up the IP for that domain by talking to Google’s 8.8.8.8 DNS servers. The Button doesn’t use the DNS server given by your home DHCP server, it insists on using Google’s. That’s pretty smart. But we can get around that.

So we need to build fences for a corral within to keep our Buttons from roaming around, or upgrading their firmware. The first step is to trick it from using Google’s DNS servers. Instead, we want it to hit our own. For this, we SSH into our OpenWRT router and edit “/etc/firewall.user”. We tell it to redirect all traffic (TCP and UDP, DNS is UDP) to our DNS server when someone tries Google’s. So add these two lines:

iptables -t nat -I PREROUTING -j DNAT --destination 8.8.8.8 --to 192.168.1.1
iptables -t nat -I PREROUTING -j DNAT --destination 8.8.4.4 --to 192.168.1.1

Then apply those changes by running

/etc/init.d/firewall restart

Now when the Button contacts 8.8.8.8, it’ll actually be talking to our router’s DNS server on 192.168.1.1. If yours is different, then change those iptables commands to point to your preferred DNS server.

The second part of our corral is to make “parker-gateway-na.amazon.com” point to a server of our choice. To do that, I edited “/etc/config/dhcp” on my router which is my router’s DNS server config. In the “config dnsmasq” section, I added this line: list address '/parker-gateway-na.amazon.com/192.168.1.88'

This tells my local DNS server that when it gets asked about “parker-gateway-na.amazon.com” it should tell everyone it’s on 192.168.1.88. You can change this to be some machine on your network, or another IP like your EC2 instance or Digital Ocean droplet or whatever. Apply the change by running /etc/init.d/dnsmasq restart

You should now be able to test this on your machine. Run dig @8.8.8.8 parker-gateway-na.amazon.com This command tells ‘dig’ to do a DNS lookup using 8.8.8.8 as the DNS server and look for ‘dig parker-gateway-na.amazon.com’. It should resolve as an A record to that IP you gave to dnsmasq.

If that’s ready and working, now you can set up your target server to serve your Buttons. I did this using nginx, and here is what my config file looks like:

server {
  listen 80;
  listen [::]:80;

  # SSL configuration
  #
  listen 443 ssl;
  listen [::]:443 ssl;
  #
  # Note: You should disable gzip for SSL traffic.
  # See: https://bugs.debian.org/773332
  #
  # Read up on ssl_ciphers to ensure a secure configuration.
  # See: https://bugs.debian.org/765782
  #
  # Self signed certs generated by the ssl-cert package
  # Don't use them in a production server!
  #
  include snippets/snakeoil.conf;

  root /code/amazon-dash/www;

  # Add index.php to the list if you are using PHP
  index index.php index.html index.htm index.nginx-debian.html;

  server_name parker-gateway-na.amazon.com;

  # To allow POST on static pages
  error_page  405     =200 $uri;

  rewrite ^/2/b$ /dash.php;

  location / {
    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;
  }

  # pass the PHP scripts to FastCGI server listening on the php-fpm socket
  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
  }
}

I’m just using PHP for this, and as you can see, I host it at “/code/amazon-dash/www”. But you can put your files wherever you want. It redirects the path that the button looks for at /2/d to “dash.php”

Here is the code in “dash.php”

<?php

$out = fopen("/tmp/dash_request.txt", "w");
$req = print_r($_SERVER, true);
$req .= print_r($_POST, true);
$bindata = file_get_contents('php://input');
$bb = print_r(str_split($bindata), true);
$id = substr($bindata, 6, 16);

$idd = sprintf("id: %s \n\n", $id);

fwrite($out, $req."\n\n".$idd."\n");
fclose($out);

$msg="";
if($id == "G030G0055XXXXXXXX")
{
        $output = shell_exec("bash /code/amazon-dash/scripts/x.sh 2>&1");
}
else if($id == "G030G0055YYYYYY")
{
        $output = shell_exec("bash /code/amazon-dash/scripts/y.sh 2>&1");
}

print($output);
?>

I am doing my best to parse out the unique ID given to each Dash button. This is that “DSN” code printed on the outside of the box it comes in. That way you can tell multiple buttons apart. And in this case, I just have the different buttons executing different shell scripts. So you can make them do whatever you want. I also set up some debugging so that info about the requests are logged to “/tmp/dash_request.txt”. I figured out only enough of the protocol to extract the unique ID. But it’s binary and I’m sure there are lots of interesting things in there that I’m missing out on. Remaining battery for example is probably one of them.

But anyway, at this point you have your little Dash Button corral to keep the buttons you own from running away. Plus they can do whatever you want them to do. If your scripts return a 200 OK HTTP response, the Buttons will even light up green to say that all is cool.

Enjoy.

Note that I don’t know how long this will last. I very much expect Amazon to issue a firmware upgrade to fix this. One thing is that the Buttons talk to parker-gateway-na.amazon.com using HTTPS. And if you take a look under the skirt of the firmware that dekuNukem kindly posted to https://github.com/dekuNukem/Amazon_Dash_Button (you can run the “strings” command on the Cottonelle.bin file he has) you’ll notice it has quite a few certificates in there. Luckily for us, in the initial release the Amazon engineers didn’t bother validating the certificates, which they probably should have. This lets our Nginx server to sit there and pretend to be “parker” and present bullshit self-signed certificates which the Dash Buttons are happily expecting. I think one of the first changes in a subsequent firmware upgrade will be to address this. But once you corral them in on your network, you can keep them from doing this.