Forging WiFi Beacon Frames Using Scapy

In this article we will show you how to use Scapy to broadcast forged beacon frames for a fake Wireless Access Point.

How does your laptop, workstation or smartphone know which wireless networks are available nearby? It's actually very simple, Wireless Access Points (often your broadband router in a SOHO environment) continually broadcast beacon frames. Beacon frames include information about the access point, such as the SSID, supported data rates and what encryption is being used. These are received by your device's wireless network interface and interpreted by your operating system to build the list of available networks.

I wanted to see if I could forge beacon frames using Scapy to add a fake wireless network to the list on my local system. Scapy is a packet manipulation library that allows sending, forging and capturing of network packets. It was written in Python and supports a wide range of protocols.

In this tutorial, we will advertise a network called "testSSID" with WPA2 security using either TKIP or AES encryption.

Creating the Python Script

To start, we need to import the Scapy modules that are going to be used:

from scapy.all import Dot11,Dot11Beacon,Dot11Elt,RadioTap,sendp,hexdump

The following variables are created and assigned the following values to form the beacon frame:

netSSID = 'testSSID' #Network name here
iface = 'wlan0mon'   #Interface name here

dot11 = Dot11(type=0, subtype=8, addr1='ff:ff:ff:ff:ff:ff',
addr2='22:22:22:22:22:22', addr3='33:33:33:33:33:33')
beacon = Dot11Beacon(cap='ESS+privacy')
essid = Dot11Elt(ID='SSID',info=netSSID, len=len(netSSID))
rsn = Dot11Elt(ID='RSNinfo', info=(
'\x01\x00'
'\x00\x0f\xac\x02'
'\x02\x00'
'\x00\x0f\xac\x04'
'\x00\x0f\xac\x02'
'\x01\x00'
'\x00\x0f\xac\x02'
'\x00\x00'))

Note you will have to make sure that "iface" is equal to the name of the interface you want to use on your device.

For the variable "dot11" the parameters mean the following:

type=0 To indicate the frame is a management frame (type 0).
subtype=8 To indicate the management frames subtype is a beacon (type 8).
addr1 Destination MAC address.
addr2 Source MAC address of sender.
addr3 MAC address of Access Point.

The "beacon" variable indicates the capabilities of our access point. Here we are saying it is an ESS network and the "privacy" parameter was required for the network to appear secured when discovered from an Apple device.

To define the network as WPA2, we need to add a Robust Secure Network (RSN) Information Element (IE) to our management frame. The variable "rsn" contains this information and is specified to Scapy in hexadecimal.

Comments on each line indicate what the hexadecimal values mean:

rsn = Dot11Elt(ID='RSNinfo', info=(
'\x01\x00'              #RSN Version 1
'\x00\x0f\xac\x02'      #Group Cipher Suite : 00-0f-ac TKIP
'\x02\x00'              #2 Pairwise Cipher Suites (next two lines)
'\x00\x0f\xac\x04'      #AES Cipher
'\x00\x0f\xac\x02'      #TKIP Cipher
'\x01\x00'              #1 Authentication Key Managment Suite (line below)
'\x00\x0f\xac\x02'      #Pre-Shared Key
'\x00\x00'))            #RSN Capabilities (no extra capabilities)

The rest of the script builds the frame and shows it before prompting the user to begin sending the frames:

frame = RadioTap()/dot11/beacon/essid/rsn

frame.show()
print("\nHexDump of frame:")
hexdump(frame)
raw_input("\nPress enter to start\n")

sendp(frame, iface=iface, inter=0.100, loop=1)

Sendp is used to send our broadcast frame. "inter=0.100" combined with "loop=1" will cause a frame to be sent every 100 milliseconds until the program is exited.

The whole script should look like the following:

from scapy.all import Dot11,Dot11Beacon,Dot11Elt,RadioTap,sendp,hexdump

netSSID = 'testSSID'       #Network name here
iface = 'wlan0mon'         #Interface name here

dot11 = Dot11(type=0, subtype=8, addr1='ff:ff:ff:ff:ff:ff',
addr2='22:22:22:22:22:22', addr3='33:33:33:33:33:33')
beacon = Dot11Beacon(cap='ESS+privacy')
essid = Dot11Elt(ID='SSID',info=netSSID, len=len(netSSID))
rsn = Dot11Elt(ID='RSNinfo', info=(
'\x01\x00'                 #RSN Version 1
'\x00\x0f\xac\x02'         #Group Cipher Suite : 00-0f-ac TKIP
'\x02\x00'                 #2 Pairwise Cipher Suites (next two lines)
'\x00\x0f\xac\x04'         #AES Cipher
'\x00\x0f\xac\x02'         #TKIP Cipher
'\x01\x00'                 #1 Authentication Key Managment Suite (line below)
'\x00\x0f\xac\x02'         #Pre-Shared Key
'\x00\x00'))               #RSN Capabilities (no extra capabilities)

frame = RadioTap()/dot11/beacon/essid/rsn

frame.show()
print("\nHexdump of frame:")
hexdump(frame)
raw_input("\nPress enter to start\n")

sendp(frame, iface=iface, inter=0.100, loop=1)

Setting a Wireless Interface to Monitor Mode

Before we run the script, we need to make sure we have the wireless interface we want to use set to monitor mode which provides access to send and receive wireless management frames. Since I am using Kali Linux, I can use the following commands to find the name of my wireless interface and set it to monitor mode.

List the wireless interfaces:

root@kali:~# airmon-ng

PHY  Interface  Driver    Chipset

phy0  wlan0     rt2800usb Ralink Technology, Corp. RT2870/RT3070

Check for running processes that could interfere with setting the interface to monitor mode:

root@kali:~# airmon-ng check

Found 2 processes that could cause trouble.
If airodump-ng, aireplay-ng or airtun-ng stops working after
a short period of time, you may want to kill (some of) them!

 PID Name
 647 NetworkManager
 755 wpa_supplicant

Killing processes that could interfere:

root@kali:~# airmon-ng check kill

Killing these processes:

 PID Name
 755 wpa_supplicant

Setting the interface to monitor mode:

root@kali:~# airmon-ng start wlan0
PHY   Interface  Driver     Chipset
phy0  wlan0      rt2800usb  Ralink Technology, Corp. RT2870/RT3070

        (mac80211 monitor mode vif enabled for [phy0]wlan0 on [phy0]wlan0mon)
        (mac80211 station mode vif disabled for [phy0]wlan0)

Note our interface was set up as wlan0mon which is set in the iface variable in our Python script.

Running the Script

Now that we have an interface in monitor mode we are ready to run the script. When running the script you should see the following information:

root@kali:~/Documents/Python# python newSSID.py
WARNING: No route found for IPv6 destination :: (no default route?)
###[ RadioTap dummy ]###
 version = 0
 pad = 0
 len = None
 present =
 notdecoded= ''
###[ 802.11 ]###
 subtype = 8
 type = Management
 proto = 0
 FCfield =
 ID = 0
 addr1 = ff:ff:ff:ff:ff:ff
 addr2 = 22:22:22:22:22:22
 addr3 = 33:33:33:33:33:33
 SC = 0
 addr4 = 00:00:00:00:00:00
###[ 802.11 Beacon ]###
 timestamp = 0
 beacon_interval= 100
 cap = ESS+privacy
###[ 802.11 Information Element ]###
 ID = SSID
 len = 8
 info = 'testSSID'
###[ 802.11 Information Element ]###
 ID = RSNinfo
 len = None
 info = '\x01\x00\x00\x0f\xac\x02\x02\x00\x00\x0f\xac\x04\x00\x0f\xac\x02\x01\x00\x00\x0f\xac\x02\x00\x00'

Hexdump of frame:
0000 00 00 08 00 00 00 00 00 80 00 00 00 FF FF FF FF ................
0010 FF FF 22 22 22 22 22 22 33 33 33 33 33 33 00 00 ..""""""333333..
0020 00 00 00 00 00 00 00 00 64 00 11 00 00 08 74 65 ........d.....te
0030 73 74 53 53 49 44 30 18 01 00 00 0F AC 02 02 00 stSSID0.........
0040 00 0F AC 04 00 0F AC 02 01 00 00 0F AC 02 00 00 ................

Press enter to start

From the above, we can confirm the structure of the beacon frame, its properties and view a hex dump of it.

Pressing enter will start broadcasting the beacon frames:

Starting broadcast frames

At this point, devices with wireless network interfaces should be able to see the network:

root@kali:~# iwlist wlan0 scan
Cell 14 - Address: 33:33:33:33:33:33
           Channel:4
           Frequency:2.427 GHz (Channel 4)
           Quality=70/70 Signal level=-31 dBm
           Encryption key:on
           ESSID:"testSSID"
           Mode:Master
           Extra:tsf=0000000000000000
           Extra: Last beacon: 2428ms ago
           IE: Unknown: 00087465737453534944
           IE: IEEE 802.11i/WPA2 Version 1
               Group Cipher : TKIP
               Pairwise Ciphers (2) : CCMP TKIP
               Authentication Suites (1) : PSK

To exit the script, press "ctrl + c".

Since we've only created wireless beacons, attempting to connect will fail as there is no real access point.

Summary

This is a simple demonstration of how easily these frames can be produced, far more complex wireless attacks exist and open source tools to perform them are available but it serves to highlight that connecting to any wireless network should be done with caution as the identity of that network cannot necessarily be trusted.

Author image

William Hurer-Mackay

Will is a Computer Networks Engineering graduate of the University of Northampton who is undertaking 4ARMED's Security Tester internship programme aimed at bringing new recruits into the cyber security sector.

Related Blog Articles