Amazon Dash Hack – Elegant

This is about using those inexpensive Amazon Dash Buttons (.com / .de) not for ordering stuff, but for useful purposes within the “Internet of Things” (IoT) scope. … Admittedly, this has been done before – but I believe that my DHCP-based approach to hijack the Dash Button is more elegant. – Watch out – heavy techno-babble ahead!

(… Sorry, keine deutschsprachige Fassung … Sorry, no German language version …)

When I first heard about those Amazon Dash Buttons in August 2016, my first thought was: “I wonder what happens if some guy hacks into its mechanism and provides a way to use them to do random other stuff instead of ordering items on Amazon.” Little did I know that these solutions had been around for a whole year already – starting with one Ted Benson who was using two Dash Buttons to count nightly baby poops and baby wake-ups. … Not to mention the awesome “Dash Button Dudes” blog.

And I realized that I simply had to have one of those to see what I could imagine doing with it. Although … The whole ARP probe snooping on Wi-Fi sounded kind of over-the-top to me. Especially as my own resident Raspberry Pi is hooked up to my house’s switched ethernet instead of Wi-Fi, which usually makes “wiresharking” significantly harder to perform.


But I had a different, much simpler idea already: For reasons which go beyond the scope of this little blog entry, my Raspi acts as my home network’s DHCP server. As soon as those above mentioned Dash hacking DIYs brought up that I had to determine the Dash Button’s MAC address after it had been configured to access the Wi-Fi, I knew that this was easy as Pi(e): I simply had to look into my (Wheezy) Pi’s /var/log/syslog right after hitting the Dash Button and simply extract the MAC via copy & paste.

… If you’ll excuse my paranoia for concealing both my private subnet and the full Dash’s MAC: Apart from that, this is what showed up in the log when I first configured the button and pressed it – and later after assigning a readable host name to that MAC, “eukanuba-dash”:

Sep 16 20:42:13 raspi dnsmasq-dhcp[30217]: DHCPDISCOVER(eth0) ac:63:be:xx:xx:xx
Sep 16 20:42:13 raspi dnsmasq-dhcp[30217]: DHCPOFFER(eth0) 192.168.xx.63 ac:63:be:xx:xx:xx
…
Sep 16 20:43:29 raspi dnsmasq-dhcp[30217]: DHCPREQUEST(eth0) 192.168.xx.63 ac:63:be:xx:xx:xx
Sep 16 20:43:29 raspi dnsmasq-dhcp[30217]: DHCPACK(eth0) 192.168.xx.63 ac:63:be:xx:xx:xx
…
Sep 18 18:12:13 raspi dnsmasq-dhcp[2582]: DHCPREQUEST(eth0) 192.168.xx.63 ac:63:be:xx:xx:xx 
Sep 18 18:12:13 raspi dnsmasq-dhcp[2582]: DHCPACK(eth0) 192.168.xx.63 ac:63:be:xx:xx:xx eukanuba-dash

Obviously I had to be sure that I caught the correct MAC address, i.e. the correct device that I was tinkering with the correct device. For such an endeavor I recommend to head over to the (e.g.) MA:CV:en:do:rs and check that the corresponding device was actually manufactured by Amazon – just to be sure. 😉

If you want to be really, really sure, try pinging the IP you found, and you’ll see that once you press the button, it will be available only for a short window of perhaps 2 seconds before it goes dark again:

geros-imac:~ gerozahn$ ping eukanuba-dash
PING eukanuba-dash (192.168.xx.63): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
64 bytes from 192.168.xx.63: icmp_seq=4 ttl=64 time=1.621 ms
64 bytes from 192.168.xx.63: icmp_seq=5 ttl=64 time=1.503 ms
Request timeout for icmp_seq 6
Request timeout for icmp_seq 7
^C
--- eukanuba-dash ping statistics ---
9 packets transmitted, 2 packets received, 77.8% packet loss
round-trip min/avg/max/stddev = 1.503/1.562/1.621/0.059 ms
geros-imac:~ gerozahn$ 

So – what now? Can I tap into this DHCP business to catch the Dash Button activity? Well – yes, it’s actually quite simple. I present you not one, but actually two different ways to achieve this, both are essentially one-liners, without the need to install Python libraries for ARP snooping.

I realize now that this turned out to be a tad lengthy, so if you really want it short, scroll down to the bottom of this entry and read the summary. 😛

Method 1: If you’re sitting on your DHCP server

This applies if your Raspi is  your DHCP server, just like mine. If that should not be the case, then method 2 further down will work without that assumption. So bear with me, it’s method 1 is worth the read as well; or otherwise, simply skip ahead (but it’ll be your loss).

One initial caveat: In case you are using dnsmasq as your DHCP server, you could imagine using the “dhcp-script” configuration option. A word of advice: Don’t. – True, the configurable script is triggered upon every DHCP lease action. But it also triggered once for any cached lease upon every restart of the dnsmasq service (and as well upon rebooting your Raspi). So this method would trigger your action without actually pressing the button. – So: Don’t use dnsmasq / dhcp-script.

Let’s simply read along the syslog instead – which can be performed quite easily and efficiently. Simply do the following and then press the Dash Button (and cancel the command with Ctrl-C after you’ve seen enough):

pi@raspi ~ $ tail -Fn0 /var/log/syslog
Sep 18 18:40:35 raspi dnsmasq-dhcp[2582]: DHCPREQUEST(eth0) 192.168.xx.63 ac:63:be:xx:xx:xx 
Sep 18 18:40:35 raspi dnsmasq-dhcp[2582]: DHCPACK(eth0) 192.168.xx.63 ac:63:be:xx:xx:xx eukanuba-dash
^C
pi@raspi ~ $

Easy enough, right? Well … Not so fast. At the moment, we receive all syslog entries. We’ll need to filter this for DHCP requests. Let’s use AWK for this – run this, press the Dash Button, and cancel with Ctrl-C:

pi@raspi ~ $ tail -Fn0 /var/log/syslog | awk -W interactive '/DHCPREQUEST/'
Sep 18 18:44:39 raspi dnsmasq-dhcp[2582]: DHCPREQUEST(eth0) 192.168.xx.63 ac:63:be:xx:xx:xx 
^C
pi@raspi ~ $

(A little background information: “-W interactive” does a so-called “de-buffering”, forcing AWK to process the incoming data line by line instead of buffering the whole stream – which will obviously never end for a log file that keeps growing.)

Not bad, right? Well … Repeating: Not so fast. At the moment we catch all DHCP requests on your whole network. This is the right moment to filter for your Dash Button’s MAC address only – we’ll do this with a tiny regular expression:

pi@raspi ~ $ tail -Fn0 /var/log/syslog | awk -W interactive 'match ($0, /DHCPREQUEST.*ac:63:be:xx:xx:xx/)'
Sep 18 18:48:43 raspi dnsmasq-dhcp[2582]: DHCPREQUEST(eth0) 192.168.xx.63 ac:63:be:xx:xx:xx 
^C
pi@raspi ~ $

The magic is in the “.*” in the middle of the regex, which skips over everything between the “DHCPREQUEST” and the MAC.


So – now we have one line of result that will be displayed whenever you press the Dash Button. How do we make use of this?

First, let’s try to figure out what exactly we’d like to do. Let’s put all that in a shell script called “eukanuba-action.bash” (named after my Dash Button’s label, see video above) and put it into a subdirectory called “dash”:

pi@raspi ~/dash $ cat eukanuba-action.bash
#!/bin/bash
echo "Pressed Eukanuba dash button"
#sudo etherwake zahn-nas
pi@raspi ~/dash $

Let’s go with the echo command first. The second line that is commented out will actually wake up my NAS as shown in the video – we’ll save that for later. — Don’t get me wrong: If you have different ideas what the button could do, and if you like Python better than bash, feel free to program a .py script instead.

Now let’s do this: The same tail / awk / regex action as above, but this time triggering the script:

pi@raspi ~/dash $ tail -Fn0 /var/log/syslog | awk -W interactive 'match($0, /DHCPREQUEST.*ac:63:be:xx:xx:xx/) {system("./eukanuba-action.bash")}'
Pressed Eukanuba dash button
^C
pi@raspi ~/dash $

Done! 🙂

So let’s make this more practical: Let’s put the tail / awk / regex / system call into a shell script called “dhcrequest-listen.bash”:

pi@raspi ~/dash $ cat dhcprequest-listen.bash 
#!/bin/bash
cd "$(dirname "$0")"
tail -Fn0 /var/log/syslog | awk -W interactive 'match($0, /DHCPREQUEST.*ac:63:be:xx:xx:xx/) {system("./eukanuba-action.bash")}'
pi@raspi ~/dash $

The “cd” line switches the current working directory to the script’s resident folder, i.a. ~/dash, to be able to call the  “eukanuba-action.bash” script. Let’s do this:

pi@raspi ~/dash $ ./dhcprequest-listen.bash 
Pressed Eukanuba dash button
^C
pi@raspi ~/dash $

Time to update “eukanuba-action.bash” to comment out the echo output, but activate the “etherwake” line. (Note: For etherwake to work properly, make sure to configure /etc/ethers – so etherwake knows which MAC to wakeup based on a symbolic device name. Otherwise you’d have to wake devices by their MAC addresses.)

Now let’s run “dhcpack-listen.bash” in the background – sort of like a homemade service. We’ll use “nohup” (short for “no hangup”), so the script will keep running in the background after you log out of your Raspi. This will do (you’ll have to hit enter once again afterwards, as the output text shows up on the prompt):

pi@raspi ~/dash $ nohup ./dhcprequest-listen.bash &
[1] 9064
pi@raspi ~/dash $ nohup: ignoring input and appending output to `nohup.out'

pi@raspi ~/dash $

This tells you the following: The script is running in the background. Try it: It should fire up your NAS or whatever you programmed it to do. … Note: If you kept the “echo” command in the script, or if your script produces any other kind of console output, you will find the output in the “nohup.out” text file.


In case you would want to stop this home-made service, it requires killing the process that is now running in the background. This turns out to be a bit tricky at this point, especially after logging off and back on to your Raspi again. But you can easily find it with the help of “ps x”:

pi@raspi ~/dash $ ps x
 PID TTY STAT TIME COMMAND
 7972 ? S 0:00 sshd: pi@pts/0 
 7973 pts/0 Ss 0:01 -bash
 9064 pts/0 S 0:00 /bin/bash ./dhcprequest-listen.bash
 9066 pts/0 S 0:00 tail -Fn0 /var/log/syslog
 9067 pts/0 S 0:00 awk -W Interactive match($0, /DHCPREQUEST.*ac:63:be:xx:xx:xx/) {system("./eukanuba-action.bash")}
 9080 pts/0 R+ 0:00 ps x
pi@raspi ~/dash $

I recommend killing the “tail” process, in this example 9066 – i.e. like this:

pi@raspi ~/dash $ kill 9066
pi@raspi ~/dash $ ps x
 PID TTY STAT TIME COMMAND
 7972 ? S 0:00 sshd: pi@pts/0 
 7973 pts/0 Ss 0:01 -bash
 9094 pts/0 R+ 0:00 ps x
pi@raspi ~/dash $

This will automatically get rid of the dependent “awk” process 9067 and as well the caller 9064.

And now we’re done. 😉

Method 2: If you don’t have access to DHCP log entries

The scenario described above works under the assumption that your Raspi is also the home network’s DHCP server, so that the Dash Button’s DHCP requests actually show up in /var/log/syslog. However, if e.g. your Wi-Fi router is acting as your DHCP server, you might have trouble seeing and let alone “tailing” that particular log file to be able to trigger scripted actions.

But here’s the beauty in this DHCP approach: DHCP requests are broadcast throughout the whole network, as a client can impossibly know which host to contact after turning on. In other words: DHCP requests are accessible on every client of your LAN / WLAN. That means that you can easily utilize another Raspi apart from your regular DHCP server, as long as it resides within that same wired or wireless network as the Dash Button, and it will still be able to listen to its DHCP requests. — Any Raspi will do, I assume that even a tiny Pi Zero will have by far enough horsepower to pull this off.

So – let’s get to that Raspi. Have it run Raspbian, and install a nice little tool named “dhcpdump”.

sudo apt-get install dhcpdump

It will also install its dependencies (in case they are not installed yet, which are “tcpdump” and “libpcap”, don’t mind those).

Now try this and hit your Dash Button:

sudo dhcpdump -i eth0

Please note: If your Raspi is using Wi-Fi instead of Ethernet, do this:

sudo dhcpdump -i wlan0

This should give you a lengthy verbose output, much longer than seen before in syslog. Don’t get confused by that: It also states that your Dash Button has successfully sent a DHCP request. … As before, you can easily find out your Dash Button’s MAC by looking at dhcpdump’s output.


Once you’ve got that (and checked it against MA:CV:en:do:rs to be sure you got the right one), you will want to filter the DHCP requests that dhcpdump sees so you’ll catch only those emanating from the Dash Button. Like this (again: you might need to change “eth0” to “wlan0” depending on how your Raspi is connected to your home network):

sudo dhcpdump -i eth0 ac:63:be:xx:xx:xx

So – how to trigger actions from this? Like above in method 1, we’ll go with AWK again:

pi@raspi ~ $ sudo dhcpdump -i eth0 ac:63:be:xx:xx:xx | awk -W interactive '/DHCPREQUEST/'
OPTION: 53 ( 1) DHCP message type 3 (DHCPREQUEST)
^C
pi@raspi ~ $

As before, instead of printing out that one line, let’s again turf this over to our above mentioned  “eukanuba-action.bash” script (which, as you know, could just as well be a Python script as well if you prefer that):

pi@raspi ~/dash $ sudo dhcpdump -i eth0 ac:63:be:xx:xx:xx | awk -W interactive '/DHCPREQUEST/ {system("./eukanuba-action.bash")}'
Pressed Eukanuba dash button
^C
pi@raspi ~/dash $

Time to update “dhcprequest-listen.bash” to use dhcpdump (instead of tailing the syslog in method 1):

pi@raspi ~/dash $ cat dhcprequest-listen.bash
#!/bin/bash
cd "$(dirname "$0")"
sudo dhcpdump -i eth0 ac:63:be:xx:xx:xx | awk -W interactive '/DHCPREQUEST/ {system("./eukanuba-action.bash")}'
pi@raspi ~/dash $

It works just as expected:

pi@raspi ~/dash $ ./dhcprequest-listen.bash
Pressed Eukanuba dash button
^C
pi@raspi ~/dash $

Let run this with “nohup” as a homemade service again, shall we?

pi@raspi ~/dash $ nohup ./dhcprequest-listen.bash &
[1] 9262
pi@raspi ~/dash $ nohup: ignoring input and appending output to `nohup.out'

pi@raspi ~/dash $

If you’ve left your “echo” command in “eukanuba-action.bash”, you’ll see it in “nohup.txt”. Other than that, it should do exactly as you programmed it to do, like e.g. waking up the NAS via etherwake.

Terminating the homemade service is a little bit more difficult now. As the dhcpdump process is running via sudo, you won’t find it with “ps x” from within your “pi” user account. So you’ll have to look for it via “ps ax | grep dhcpdump”:

pi@raspi ~/dash $ ps x
 PID TTY STAT TIME COMMAND
 9262 ? S 0:00 /bin/bash ./dhcprequest-listen.bash
 9265 ? S 0:00 awk -W Interactive /DHCPREQUEST/ {system("./eukanuba-action.bash")}
 9272 ? S 0:00 sshd: pi@pts/0 
 9273 pts/0 Ss 0:01 -bash
 9400 pts/0 R+ 0:00 ps x
pi@raspi ~/dash $ ps aux | grep dhcpdump
root 9264 0.0 0.2 3112 2264 ? S 19:58 0:00 sudo dhcpdump -i eth0 ac:63:be:xx:xx:xx
root 9266 0.0 0.4 4856 4144 ? S 19:58 0:00 dhcpdump -i eth0 ac:63:be:xx:xx:xx
pi@raspi ~/dash $

As you can see, dhcpdump is running inside the root user context. I recommend killing exactly that one, i.e. in this case 9264:

pi@raspi ~/dash $ sudo kill 9264
pi@raspi ~/dash $ ps x
 PID TTY STAT TIME COMMAND
 9272 ? S 0:00 sshd: pi@pts/0 
 9273 pts/0 Ss 0:01 -bash
 9417 pts/0 R+ 0:00 ps x
pi@raspi ~/dash $ ps aux | grep dhcpdump
pi@raspi ~/dash $

Done.

I’d like to conclude that the “dhcpdump” also works if you are on your DHCP server. So it is more universal than tailing the syslog, and I guess it should be preferred over method 1, especially if you can’t get ahold of a log file containing the Dash Button’s DHCP requests.

Summary

I know, I know – tl;dr. So just skim over this final paragraph and skip back into the full text for the details. It’s all there, you know. 😉

So: To execute random actions when pressing an Amazon Dash Button, do this:

  1. Get a Dash Button and configure it to be accessing the Wi-Fi, but don’t configure an item to be ordered.
  2. Now get a Raspberry Pi and place it within the same LAN / WLAN as the Dash Button.
  3. Figure out what you’d like to achieve when pressing the button, then program that into a shell script or a Python script … or whatever your poison is.
  4. Install the tool “dhcpdump” together with its dependencies (which is “tcpdump” and “libpcap”) on your Raspi.
  5. Run “sudo dhcpdump -i eth0” (replace “eth0” with “wlan0” if applicable) and press your Dash Button. This way, you will easily find out your Dash Button’s MAC address.
  6. The following one-liner with “yo:ur:da:sh:sm:ac” replaced by your dash’s MAC and “whatever-you-named-your-script” replaced by the path and name to your script
    sudo dhcpdump -i eth0 yo:ur:da:sh:sm:ac | awk -W interactive '/DHCPREQUEST/ {system("whatever-you-named-your-script")}'

    will do the magic.

  7. Run that one-liner via “nohup … &”. This way, you can log off from your Raspi, while this home-made service will keep running in the background.
  8. To terminatethe home-made service, find the “sudo dhcpdump” process with „ps aux | grep dhcpdump“ and kill that with “sudo kill …”.

Done.


Admitted: This is kind of nerdy, but it’s actually rather easy and and pretty straightforward, compared to the usual ARP snooping stuff via Python.

Keine Kommentare möglich.