IoT – The WiFi Probe REQ an RTLS. Tracking WiFi Devices for a penny.


Every WiFi enabled device that you have (laptop, phone, tablet, kindle, watch, … ) is sending a PROBE REQuest packets in background to figure out if there are any known AP’s.
It’s done transparently, wether you are in a shopping center, outside in a park, or in the mountains – it’s a continuous process.
If an AP is found the device automatically associates to let you stay online ASAP. This is built in the 802.11 protocol. (More)

Knowing that every single device is broadcasting a Probe packet i figured out that it might be interesting to place couple of ESP8266 around with sniffer mode enabled to listen to these Probe Requests and forward them to a central server for analysis. The idea behind that is to be able to track every device between zones (places where ESP8266 are located) and guess what, i had couple of hours free to code and try it out.

I placed couple of nodes in different places within the city and enabled sniffer mode that looks for 0x40 802.11 type packets (PROBE REQUEST). When a packet is received it is sent out to a central server where packets are stored and presented later on on a web page.

This time i used ESP8266 on a ‘Witty’ chip – it’s a cool 2cmx2cm sized board that has a single button, rgb led built in and obviously an USB power. Pretty cheap, you can get tons of them for almost ‘no money’.

Every single ESP8266 device in this system that listens for packets is called ZONE, so if you place 4 of them in different locations – you have 4 zones. I have placed 2 of them for tests, one in the Garage and one outside in the area where i live. This is to figure out if i can determine wether people (and at what time) travel between garage and main area, how often and at what time. Time for a start, ESP’s placed, kick started – analysis time.


The above graph shows number of packets for every hour in last 24hours, there’s a quite number of packets received as you can see, big-data time 😉

As i have two zones, let’s see how active they are – meaning, when was the last packet received at which zone – this helps me out to determine the Per-zone activity and eventual down-times of the zone nodes.


You can clearly see that both zones received their last packets 2/3 seconds ago – so somebody was hanging around there with a device sending probe requests, good! Let’s move on, let’s find out what is the packet per zone distribution.


Sensible, the MAIN zone that is outside in the main area of my home is definitely more active, garage makes only 6.7% of all the packets received. Let’s find out what happened in GARAGE in last 24 hours.


Ahh more graphs, more stats – fantastic. GARAGE Zone received 62 Probe packets in last 24hrs, the peak was around 7 am (where people started to jump into their cars to drive to work).  In total there are 17 UNIQUE devices found, so potentially we can assume there were 17 persons in the zone. Need more info…


Brilliant, i can see which device was the most ‘popular’ one, meaning was having the biggest ratio of PROBEs sent across the 24hrs time and in total. Beside i can see live packets coming in from the ESP. Let’s look at this B0:79 – looks like the most popular one, a single click on the device and we’re entering a Device tracker sub-page where..


I can figure out that it is a Motorola device (based on MAC OUI) and


This Motorola sent 32 packets in last 24hrs, it was seen only in one zone (GARAGE) and it was most active today at 07:00 AM. Great, let’s go deeper…


Above is a confirmation of the fact that Motorola was seen only in Garage (wasn’t captured by MAIN zone) – live packets on the right hand side. But let’s see the whole history of this device shall we?


You can clearly look at each of the devices found and track it’s activitiy. What’s even more i can see the RSSI value – that tells me the distance of the device to the zone node.
This Motorola was first found today at 02:52 AM, interesting. The RSSI tells me it was probably on the opposite side of the garage (which is quite big) – meaning far away from the node! Knowing the Garage i can immediately figure out where this person was moving.

Let’s go back and pick up different device.



This one is more interesting, somebody was seen in both zones with this device, i wonder at what distance and time.


First seen at 7:54 today, wen to a garage (7:55) and was pretty close to the NODE at 7:56. Then the signal is getting weaker (jumped into the car probably) as minute later the signal was lost.

As you can see a simple system that costs $3.20 for each node can be turned into a quite sensible real time location service. Knowing that a deployment of 100 of nodes is still low cost – you can imagine how this can help out in business stats, emergency tracking, and advertisement targetting systems (tv screens knowing the profiles  (vendor) of candidates per week/month/season can push targeted ads). There is a big space for project like this to go live and for sale. It’s nothing new – but it’s definitely the most affordable one you can get ($3.20 for a node!).



In terms of the project – i keep it live, costs almost nothing so i’ll be adding nodes just for fun 😉

Update. I recalculate RSSI to Meters (distance), it makes more sense now.



Spooky and PS_POLL incident

Just placed a new Spooky at my apartment on the balcony.
Btw, every time a blue internal led blinks – it means Spooky has parsed a packet.

And guess what next?


Just got a notification after couple of hours running of a PS_POLL traveling from unknown to unknown.

Zrzut ekranu 2016-08-04 o 20.22.17

A PS_POLL frame indicates (in shortcut) that some device went sleep and checks at some point wether there is any packet queued on the AP to be received.

To assist stations with power saving, Access Points (APs) are designed to buffer frames for a station when that station is in power save mode and to transmit them later to the station when the AP knows the station will listen. When a station is in power save mode, it turns off its transmitter and receiver to preserve energy. It takes less power for a station to turn its receiver on to listen to frames than to turn it its transmitter on to transmit frames. For this reason, it’s more power-efficient for an AP to inform a station if it has buffered frames present on the AP than to have the station poll the AP querying if frames are present.

…if its sees that the AP has buffered frames for it, it must send a Power Save Poll (PS-Poll) control frame to retrieve each buffered frame on the AP

So far so good, but i don’t recognize source and destination here.
First let’s find out if there is any packet flying over WiFi with these MAC addresses.

root@kali:~# airodump-ng wlan0mon

Comes back with
Zrzut ekranu 2016-08-04 o 20.47.07

It doesn’t ring a bell, this is not my AP, Spooky is monitoring for A4:2B:8C:18:59:BA.
So it looks like a station (18:E2:C2:21:BE:68) is sending PS_POLL to AP(DC:53:7C:99:E8:97) and has my BSSID(A4:2B:8C:18:59:BA)..

Let’s find out if i can sniff 18:E2 in the air…

Zrzut ekranu 2016-08-04 o 21.08.40

And this station is certainly associated with the strange AP.

Zrzut ekranu 2016-08-04 o 21.09.10

A quick MAC Vendor check returns
Zrzut ekranu 2016-08-04 o 21.09.58

So most probably this is a phone.
Still i don’t understand why is it trying to push PS_POLL to my BSSID ?

Let’s mark this as “Investigation in progress”.

ESP8266 – WIDS – “Spooky”

Okay this is both #ESP8266 and #Security.

When i first got my hands on the ESP8266 i was curious how much can be done with the chip in terms of security. Knowing that the chip can go ‘monitor’ mode it was clear to me that first thing i’ll code would be the Wireless Intrusion Detection thing running on a 5v low power chip. At that time i ordered something what is called #NODEMCU and the fun started.


The chip itself is capable of running a callback on ever packet it receives with a function:

static void ICACHE_FLASH_ATTR handle_pkt(uint8_t* buf, uint16_t len)

There is actually an official “Sniffer” PDF document by Espressif, google it for more details.

So the way Spooky works is simple. It captures packets within BSSID that is your local home Access Point. When a packet is received, it scans through 802.11 to find the source and destination. If Source or Destination is not listed on the ‘trusted mac’s’ list then it adds this traffic to a list that is then sent out to your Gmail account every hour.

So long story short, Spooky monitors for a non-trusted traffic (that has to be defined by user) and reports it when found via E-Mail, see below for example.

A Spooky generated e-mail notifying of unknown traffic (this is an unknown device authenticating on my AP)



And a simple configuration page with trusted devices added


static void ICACHE_FLASH_ATTR handle_pkt(uint8_t* buf, uint16_t len)

So how is this all programmed?
Firstly all is coded in C with Arduino IDE – it’s just great we can code chips with C. It was my first adventure with chip programming and i was very happy i didn’t have to lear myself some ASM or other script-kiddie language around.

The code itself is very easy, ESP8266 has a file system (SPIFF) so the configuration is loaded/stored directly from that file. I could easily skip writing/reading from EEPROM thanks to this.

All these Web server things are built in and available as ready to use classes so i will not go into details with that.

The Sniffer Callback function has to be very quickly executed or WatchDog will restart the chip, so there is no room and space and time for a lot of work to do. Knowing that i am only doing quick 802.11 inspection to find out RSSI, BSSID, Source, Destination and packet type in accordance to the below 802.11 header


First i find out the packet type by defining them as below:
Zrzut ekranu 2016-08-04 o 10.58.11

Then i filter out all Beacon and Probe request type of frames as they fly around and Spooky will identify them as unknown traffic. So i’m looking only after DATA and MANAGEMENT type frames that are Directed towards user selected Access Point BSSID. This is how i get only the interesting packets out of the chaos around.

Next i read out Source / Destination by looking into ToDS FromDS fields – these are swapped around in regards to the frame type, so be careful how you read them. An example below:

Zrzut ekranu 2016-08-04 o 10.57.11

Then we get the RSSI of the packet, this is easily taken from ESPRESSIF RxControl header within 802.11.

At this moment Spooky knows:
– What is the Packet type
– What BSSID is packet traveling within
– What source is this packet coming from
– What destination is this packet going to

Now having all above and list of trusted MAC addresses, it is easy for Spooky to identify wether a traffic directed within a defined BSSID is trusted or non trusted.
Anything coming from/to a MAC address that is not on the trusted list and having BSSID as defined by user is considered untrusted – and Spooky will email you the details.
All the rest is trusted so Spooky will ignore the traffic.

So the idea of using Spooky is quite simple:
Whenever you get an untrusted traffic notification from Spooky – you either block the MAC address on your Router (if you can’t identify it) or add it to Spooky Trusted MAC’s list (if you know the MAC).

Thanks to this you keep your AP safe and you are notified of unknown events. The word Notified is important because you don’t have to check your AP logs (who does it anyway?)  for intruders and you can respond to events immediately. And yes i know routers can be configured to block untrusted MACs, but i never used that option.

Spooky went into release and some of the users even made a small TicTac version of it.


I expect to make some 3d printed cube for spooky in free time. If you are interested in the code i will be posting it shortly.