Thursday, January 16, 2014

Sending 802.11 Packets with Scapy


To accompany my recent technical segment on Paul Assadorian's Security Weekly show, here is a functional Python example of sending 802.11 beacons, probe requests, ARP and DNS requests.   Enjoy!



#!/usr/bin/env python

"""
802.11 Scapy Packet Example
Author: Joff Thyer, 2014
"""

# if we set logging to ERROR level, it supresses the warning message
# from Scapy about ipv6 routing
#   WARNING: No route found for IPv6 destination :: (no default route?)
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *


class Scapy80211():

    def  __init__(self,intf='wlan0',ssid='test',\
          source='00:00:de:ad:be:ef',\
          bssid='00:11:22:33:44:55',srcip='10.10.10.10'):

      self.rates = "\x03\x12\x96\x18\x24\x30\x48\x60"

      self.ssid    = ssid
      self.source  = source
      self.srcip   = srcip
      self.bssid   = bssid
      self.intf    = intf
      self.intfmon = intf + 'mon'

      # set Scapy conf.iface
      conf.iface = self.intfmon

      # create monitor interface using iw
      cmd = '/sbin/iw dev %s interface add %s type monitor >/dev/null 2>&1' \
        % (self.intf, self.intfmon)
      try:
        os.system(cmd)
      except:
        raise


    def Beacon(self,count=10,ssid='',dst='ff:ff:ff:ff:ff:ff'):
      if not ssid: ssid=self.ssid
      beacon = Dot11Beacon(cap=0x2104)
      essid  = Dot11Elt(ID='SSID',info=ssid)
      rates  = Dot11Elt(ID='Rates',info=self.rates)
      dsset  = Dot11Elt(ID='DSset',info='\x01')
      tim    = Dot11Elt(ID='TIM',info='\x00\x01\x00\x00')
      pkt = RadioTap()\
        /Dot11(type=0,subtype=8,addr1=dst,addr2=self.source,addr3=self.bssid)\
        /beacon/essid/rates/dsset/tim

      print '[*] 802.11 Beacon: SSID=[%s], count=%d' % (ssid,count)
      try:
        sendp(pkt,iface=self.intfmon,count=count,inter=0.1,verbose=0)
      except:
        raise


    def ProbeReq(self,count=10,ssid='',dst='ff:ff:ff:ff:ff:ff'):
      if not ssid: ssid=self.ssid
      param = Dot11ProbeReq()
      essid = Dot11Elt(ID='SSID',info=ssid)
      rates  = Dot11Elt(ID='Rates',info=self.rates)
      dsset = Dot11Elt(ID='DSset',info='\x01')
      pkt = RadioTap()\
        /Dot11(type=0,subtype=4,addr1=dst,addr2=self.source,addr3=self.bssid)\
        /param/essid/rates/dsset

      print '[*] 802.11 Probe Request: SSID=[%s], count=%d' % (ssid,count)
      try:
        sendp(pkt,count=count,inter=0.1,verbose=0)
      except:
        raise



    def ARP(self,targetip,count=1,toDS=False):
      if not targetip: return

      arp = LLC()/SNAP()/ARP(op='who-has',psrc=self.srcip,pdst=targetip,hwsrc=self.source)
      if toDS:
        pkt = RadioTap()\
                /Dot11(type=2,subtype=32,FCfield='to-DS',\
                addr1=self.bssid,addr2=self.source,addr3='ff:ff:ff:ff:ff:ff')\
                /arp
      else:
        pkt = RadioTap()\
                /Dot11(type=2,subtype=32,\
                addr1='ff:ff:ff:ff:ff:ff',addr2=self.source,addr3=self.bssid)\
                /arp

      print '[*] ARP Req: who-has %s' % (targetip)
      try:
        sendp(pkt,inter=0.1,verbose=0,count=count)
      except:
        raise

      ans = sniff(lfilter = lambda x: x.haslayer(ARP) and x.op == 2,
        store=1,count=1,timeout=1)

      if len(ans) > 0:
        return ans[0][ARP].hwsrc
      else:
        return None


    def DNSQuery(self,query='www.google.com',qtype='A',ns=None,count=1,toDS=False):
      if ns == None: return
      dstmac = self.ARP(ns)

      dns = LLC()/SNAP()/IP(src=self.srcip,dst=ns)/\
        UDP(sport=random.randint(49152,65535),dport=53)/\
        DNS(qd=DNSQR(qname=query,qtype=qtype))

      if toDS:
        pkt = RadioTap()\
                /Dot11(type=2,subtype=32,FCfield='to-DS',\
                addr1=self.bssid,addr2=self.source,addr3=dstmac)/dns
      else:
        pkt = RadioTap()\
                /Dot11(type=2,subtype=32,\
                addr1=dstmac,addr2=self.source,addr3=self.bssid)/dns

      print '[*] DNS query %s (%s) -> %s?' % (query,qtype,ns)
      try:
        sendp(pkt,count=count,verbose=0)
      except:
        raise

# main routine
if __name__ == "__main__":
    print """
[*] 802.11 Scapy Packet Crafting Example
[*] Assumes 'wlan0' is your wireless NIC!
[*] Author: Joff Thyer, 2014
"""
    sdot11 = Scapy80211(intf='wlan0')
    sdot11.Beacon()
    sdot11.ProbeReq()
    sdot11.DNSQuery(ns='10.10.10.2')


6 comments:

Unknown said...

Hi, I get the following error while running this program. Could you please look into this and help me debug it??

Traceback (most recent call last):
File "packets.py", line 139, in
sdot11.Beacon()
File "packets.py", line 55, in Beacon
sendp(pkt,iface=self.intfmon,count=count,inter=0.1,verbose=0)
File "/usr/lib/python2.7/dist-packages/scapy/sendrecv.py", line 259, in sendp
__gen_send(conf.L2socket(iface=iface, *args, **kargs), x, inter=inter, loop=loop, count=count, verbose=verbose, realtime=realtime)
File "/usr/lib/python2.7/dist-packages/scapy/sendrecv.py", line 234, in __gen_send
s.send(p)
File "/usr/lib/python2.7/dist-packages/scapy/supersocket.py", line 34, in send
return self.outs.send(sx)
socket.error: [Errno 100] Network is down

k said...

Hi,Did you fix the problem?

Unknown said...

Can u tell me how to run 802.11 programs?

Pawel Szczur said...

I've run your code. It runs. I setup other interface to monitor all traffic but could not capture packages.

Elizabeth J. Neal said...

You have done a amazing job with you website surveillance cameras killeen

Anonymous said...

Slots 1x2 Casino & Sports Betting Platform - Royal Ascot
Slots 1x2 is a casino and sports betting platform offering a where can i buy air jordan 18 retro toro mens sneakers simple air jordan 18 retro red to me and bestest air jordan 18 retro secure way of playing and betting on buy jordan 18 white royal blue the air jordan 18 retro men red to good site go. It's simple and secure, it's fast,