From charlesreid1

This shows an application of Scapy to create an AP scanner. This shows how to utilize Scapy to filter packets and look specifically for beacon packets.

This code is authored by iphelix and is available here: http://www.thesprawl.org/projects/airoscapy/

The Summary

This script consists of three pieces:

  • sniffAP() function, which processes packets and looks for beacons or probe responses
  • channel_hopper() function, which hops from channel to channel, spending 1 second on each channel
  • signal_handler() function, which cleans up at the end of the program and prints summary statistics

The main method then begins Scapy's sniffer, passing all packets through the sniffAP function.

To run the code, you will first need to put your wireless card into monitor mode:

ifconfig wlan1 down
iwconfig wlan1 mode monitor
ifconfig wlan1 up

then pass the same interface as an argument to the script:

$ python ap_scanner.py wlan1

The Code

ap_scanner.py

#!/usr/bin/env python
# airoscapy.py - Wireless AP scanner based on scapy
# version: 0.2
# Author: iphelix
import sys, os, signal
from multiprocessing import Process

from scapy.all import *

interface='' # monitor interface
aps = {} # dictionary to store unique APs

# process unique sniffed Beacons and ProbeResponses. 
def sniffAP(p):
    if ( (p.haslayer(Dot11Beacon) or p.haslayer(Dot11ProbeResp)) 
                 and not aps.has_key(p[Dot11].addr3)):
        ssid       = p[Dot11Elt].info
        bssid      = p[Dot11].addr3    
        channel    = int( ord(p[Dot11Elt:3].info))
        capability = p.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}\
                {Dot11ProbeResp:%Dot11ProbeResp.cap%}")
        
        # Check for encrypted networks
        if re.search("privacy", capability): enc = 'Y'
        else: enc  = 'N'

        # Save discovered AP
        aps[p[Dot11].addr3] = enc

        # Display discovered AP    
        print "%02d  %s  %s %s" % (int(channel), enc, bssid, ssid) 

# Channel hopper
def channel_hopper():
    while True:
        try:
            channel = random.randrange(1,15)
            os.system("iw dev %s set channel %d" % (interface, channel))
            time.sleep(1)
        except KeyboardInterrupt:
            break

# Capture interrupt signal and cleanup before exiting
def signal_handler(signal, frame):
    p.terminate()
    p.join()

    print "\n-=-=-=-=-=  STATISTICS =-=-=-=-=-=-"
    print "Total APs found: %d" % len(aps)
    print "Encrypted APs  : %d" % len([ap for ap in aps if aps[ap] =='Y'])
    print "Unencrypted APs: %d" % len([ap for ap in aps if aps[ap] =='N'])

    sys.exit(0)

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "Usage %s monitor_interface" % sys.argv[0]
        sys.exit(1)

    interface = sys.argv[1]

    # Print the program header
    print "-=-=-=-=-=-= AIROSCAPY =-=-=-=-=-=-"
    print "CH ENC BSSID             SSID"

    # Start the channel hopper
    p = Process(target = channel_hopper)
    p.start()

    # Capture CTRL-C
    signal.signal(signal.SIGINT, signal_handler)

    # Start the sniffer
    sniff(iface=interface,prn=sniffAP)

The Pieces

Let's break down each piece.

Packet Handling

The sniffAP() function, which is passed to the Scapy sniff() function call, is used to process each packet.

def sniffAP(p):
    if ( (p.haslayer(Dot11Beacon) or p.haslayer(Dot11ProbeResp)) 
                 and not aps.has_key(p[Dot11].addr3)):
        ssid       = p[Dot11Elt].info
        bssid      = p[Dot11].addr3    
        channel    = int( ord(p[Dot11Elt:3].info))
        capability = p.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}\
                {Dot11ProbeResp:%Dot11ProbeResp.cap%}")
        
        # Check for encrypted networks
        if re.search("privacy", capability): enc = 'Y'
        else: enc  = 'N'

        # Save discovered AP
        aps[p[Dot11].addr3] = enc

        # Display discovered AP    
        print "%02d  %s  %s %s" % (int(channel), enc, bssid, ssid) 

Channel Hopper

A function to hop among channels:

def channel_hopper():
    while True:
        try:
            channel = random.randrange(1,12)
            os.system("iw dev %s set channel %d" % (interface, channel))
            time.sleep(1)
        except KeyboardInterrupt:
            break

Cleanup

A function to cleanup when the program ends:

def signal_handler(signal, frame):
    p.terminate()
    p.join()

    print "\n-=-=-=-=-=  STATISTICS =-=-=-=-=-=-"
    print "Total APs found: %d" % len(aps)
    print "Encrypted APs  : %d" % len([ap for ap in aps if aps[ap] =='Y'])
    print "Unencrypted APs: %d" % len([ap for ap in aps if aps[ap] =='N'])

    sys.exit(0)

Main Function

The main function prints out a header for information, sets up a listener for a Control-C, and begins the Scapy sniffer.

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "Usage %s monitor_interface" % sys.argv[0]
        sys.exit(1)

    interface = sys.argv[1]

    # Print the program header
    print "-=-=-=-=-=-= AIROSCAPY =-=-=-=-=-=-"
    print "CH ENC BSSID             SSID"

    # Start the channel hopper
    p = Process(target = channel_hopper)
    p.start()

    # Capture CTRL-C
    signal.signal(signal.SIGINT, signal_handler)

    # Start the sniffer
    sniff(iface=interface,prn=sniffAP)


Flags