Attacking Pixels - Adam Robinson

Hi, I’m Adam Robinson, a software engineer and maker based in London

Take a look at my projects and experiments.

Search 17 Posts

Wi-Fi Packet Scanning With a Raspberry Pi

Posted 1 year ago - 5 min read

Tags : Ethical HackingNetworksPython

For more detial on how to set a Raspberry Pi like this check out my Ethical Hacking with a Raspberry Pi guide.

Wi-Fi Wardriving

Wardriving is the act of searching for Wi-Fi wireless networks, usually from a moving vehicle, using a laptop or smartphone. With a network receiver (monitor mode Wi-Fi adapter) you can passively scan for Access Point Beacons and when you find one append GPS data to record the location of the wireless network. With this method, you can map all of the Wi-Fi networks details and their security protocols within your area. The most popular project for Wi-Fi wardriving is WiGLE.

Capturing Probe Requests

With a bit of modification to a wardriving setup, you can also scan for different Wi-Fi frames such as Probe Requests. Probe requests may contain the broadcasting devices unique MAC address (if software-based MAC address randomisation is not adopted) and an SSID (network name) of a previously trusted wireless network the broadcasting device is searching. Using a wardriving database such as WiGLE you can potentially geolocate the wireless network a device is requesting. With enough geolocated network names, you can potentially build a picture of where a device has been. For my University of Birmingham Computer Science M.Sc, I carried out a project testing this theory: The Visualisation and analysis of device footprints through 802.11 probe request frames.

Raspberry Pi Set-up

To gather the dataset for my project I built a packet sniffing device based around a Raspberry Pi 3 B+. The Raspberry Pi ran Kali Linux Re4son - Sticky Fingers Fork used a monitor mode compatible Wi-Fi adapter (Alfa AWUS036NEH), GPS receiver (GlobalSat BU-353) and ran my python script. This Python script allows you to capture network management packets (probe requests) being broadcast from devices, the co-ordinates from where they been discovered, device manufacturers and the networks being searched for, in CSV format.

This set up was powered using a 10,000mAh battery pack ran for around 4 hours, dependent on the levels of GPS & WI-Fi activity received.

Using a Bluetooth keyboard and the 3.5” TFT running from the Raspberry Pi’s GPIO (General Purpose Input Output) interface, the system could be operated anywhere. This focus on portability removed the need to SSH into the Raspberry Pi.

Rasberry Pi Sniffer

ALFA AWUS036NEH Wireless Adapter to Monitor Mode

The adapter comes equipped with a removable high gain aerial which out of the box gives quite impressive range, and uses the Ralink RT3070 Chipset which was capable of being switched into monitor mode. Terminal commands demonstrating turning the chosen adapter from station mode into monitor mode using airmon-ng on Kali Linux can be seen bellow;

Airmon-NG

Running the Python Wifi Packet Capture Script

The script I wrote to run on this set up can be cloned from the following git repository. Python is not my main programming language so it’s probably a bit long winded but it’s functional.

# git clone https://github.com/adamistheanswer/PiSniffer

Before running the script you will need to use two tools in the Aircrack-ng suite. Airmon-ng is used to turn your wifi adapter into monitor mode. Airodump-ng takes the id of your monitoring adapter and changes it into a channel switching mode. This will allow you to cover all 14 Wi-Fi channels to capture probe requests on.

# airmon-ng start wlan0
# airodump-ng wlan0mon

Lastly in a new terminal window navigate to where you have downloaded the script and run the following command (passing the monitor mode device id and an output file name.

# python sniffGPS.py -m wlan0mon -f [output file name]

Rasberry Pi Sniffer Run

Bingo! If it’s working you should see the script continuously logging a list of the wifi packets its received a CSV.

Python Script Explained

In my sctipt I made use of the scapy packet capture library in python. The following snippet of code handles probe requests in the rotating logger. If I can sucsessfully outline whats going on here then you should be able to dive into the code and work out how I’m handeling the other wifi packets 🀞

# Check if packet is a probe request
if packet.haslayer(Dot11ProbeReq):
# Probe array will be converted to a comma seperated string fitting the csv format
# Radio strength (rssi) and channel functions get parameters from radio = str(packet.mysummary
# gpsLat & gpsLon handled by pynmea2
# str(packet.addr2) broardcasting devices MAC address
            probe = ['PR-REQ', rssi(radio), channel(radio) + 'Mhz', log_time,
                     str(gpsLat[-1])[:7], str(gpsLon[-1])[:7], 'Client', str(packet.addr2)]

# Append a hardware vendor to probe array or determine if MAC Address randomined
# clientOUI = str(packet.addr2)
# Checks here if broadcasting MAC address equal to a known hardware Vendor if so add it.
# OUI Vendor look up is added to memory at start of script from a .txt file
            if OUIMEM.get(clientOUI) is not None:
                identifiers = len(OUIMEM[clientOUI])
                if identifiers == 2:
                    probe.append(str(OUIMEM[clientOUI][1]).replace(',', '').title())
                else:
                    if identifiers == 1:
                        probe.append(str(OUIMEM[clientOUI][0]).replace(',', '').title())
            else:
# binaryRep = str(bin(int(firstOctet, scale))[2:].zfill(num_of_bits))
# 7th bit in 48-bit MAC address distinguishes universally unique or locally administered.
# Local = MAC Randomisation
                if binaryRep[6:7] == '1':
                    probe.append('Locally Assigned')
                else:
                    probe.append('Unknown OUI')
# Lastly append the SSID in the probe request. If its not there it's an undirected probe request
            if '\x00' not in packet[Dot11ProbeReq].info:
                if str(packet.info):
                    probe.append(str(packet.info))
                else:
                    probe.append('Undirected Probe')
# CSVDelim = new line and output
            logger.info(CSVDelim.join(probe))

Adam G Robinson
Crafter. Explorer. Coder. πŸ‡¬πŸ‡§