Detecting the new Amazon Dash buttons

There’s been discussion[1][2][3] about how the new Dash Buttons (model #JK291P) have been difficult to detect on the network. In theory, the buttons (including the older model #JK76PL) broadcast ARP probes to the local network each time the button is pressed. The issue is that the published filters from FamiLAB and this Medium post and this repo and several others all filter by ARP packets, and then also by the source IP == 0.0.0.0. The idea is that you only get one of these packets for each button press. However, with the new buttons, you don’t always get one of the packets! On my network, after the first button press, the button broadcasts a DHCP request first, and then the ARP broadcast has a source corresponding to the IP the button has acquired. Rather than trying to be clever about what the buttons will send and narrowing down to a single packet per button press, we can just filter by time. After all, it takes at least 5 seconds to repeat press a button, and all the packets received from button will come in much less than 5 seconds. So we can simply ignore all packets subsequently received within 5 seconds.

I’ve also modified the script to filter the sniffing by MAC address, which is slightly more efficient then filtering by ARPs, especially if there are a lot devices on your network.

It turns out that there’s a nice API to WhatsApp. I took the easy way and call the demo app from the script to send messages.

# derived from FamiLAB
import logging # for the following line
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) # suppress IPV6 warning on startup
from scapy.all import * # for sniffing for the ARP packets
import requests # for posting to the IFTTT Maker Channel
import time
import code
 
print('Init done.')

lasttime = {}
buttons = { 'goldfish': '11:22:33:44:55:66',
            'ziploc': 'aa:bb:cc:dd:ee:ff'}

def arp_display(pkt):
    wa_login = '15555552121'
    wa_password = '[somepassword]'
    wa_dest = '15555551212'
    wa_msg = '"Button was pressed!"'
    cmd = 'yowsup-cli demos -l '+wa_login+':'+wa_password+' -s '+wa_dest+' '+wa_msg
    if not pkt.haslayer(Ether):
        return
    print pkt[Ether].src, pkt.summary()

    # ignore additional packets received within min_interval seconds
    mac = pkt[Ether].src
    min_interval = 5    # seconds
    global lasttime
    if not (mac in lasttime):
        interval = min_interval + 1     # we haven't see this; generate a fire
    else:
        interval = time.time() - lasttime[mac]

    if interval >= min_interval:
        lasttime[mac] = time.time()
        if mac == buttons['goldfish']:
            # post to IFTTT
            requests.post("https://maker.ifttt.com/trigger/buttonpress/with/key/[mysecretkey]")
        elif mac == buttons['ziploc']:
            # send a WhatsApp message
            subprocess.Popen(cmd, shell=True)
        else:
            print 'We got a stray packet from an unknown device. Probably just Skynet.'

f = " or ".join(["ether host " + buttons[button] for button in buttons])
print f
print(sniff(iface="en1", prn=arp_display, filter=f, store=0))
This entry was posted in Pub. Bookmark the permalink.

Leave a Reply

Your email address will not be published.