pythonsecuritywifiscapywpa

How to use Scapy to determine WPA Encryption?


I am working on a project to detect wireless encryption in Beacon and ProbeResponse packets with Scapy.

I used a solution of another question on stackoverflow How to use Scapy to determine Wireless Encryption Type?

This is my current script:

p = pkt[Dot11Elt]

essid, channel = None, None
cryptoSet = set()

while isinstance(p, Dot11Elt):
    if p.ID == 0:
        essid = p.info.decode("utf-8", "replace")
    elif p.ID == 3:
        channel = ord(p.info)
    elif p.ID == 48:
        cryptoSet.add("WPA2")
    elif p.ID == 221 and p.info.startswith(b"\x00\x50\xf2\x01\x01\x00"):
        cryptoSet.add("WPA")
    p = p.payload

if not cryptoSet:
    cap = pkt.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}"
                      "{Dot11ProbeResp:%Dot11ProbeResp.cap%}").split('+')
    if "privacy" in cap:
            cryptoSet.add("WEP")
    else:
            cryptoSet.add("OPN")
crypto = "/".join(cryptoSet)

The script detect SSID, channel, WPA2, WEP and OPN. But when I get a packet with WPA and ID 221 I get an error.

AttributeError: 'p' object has no attribute 'info'

So I need a different way to solve this.

I am using Python 3.5.3 and Scapy 2.4.0.dev581. Dev because I need the RSSI too. This is solved in the current dev version.

Any ideas how to fix this?


Solution

  • The code you are using assumes the info tag exist on all dot11 elements. This used to be true when most of them were not implemented. (was added back as backward compatibility feature). Nowadays, scapy is supporting some more (such as WPA Microsoft vendor-specific), which do not. The code you linked is now outdated

    However in (very) latest scapy development version, there is now a special function that will always stay consistent: network_stats which implement the code you showed:

    data = b'\x00\x00\x12\x00.H\x00\x00\x00\x02\x8f\t\xa0\x00\x01\x01\x00\x00\x80\x00\x00\x00\xff\xff\xff\xff\xff\xffDH\xc1\xb7\xf0uDH\xc1\xb7\xf0u\x10\xb7\x00\x00\x00\x00\x00\x00\x00\x00\x90\x01\x11\x00\x00\x06SSID76\x01\n\x82\x84\x0c\x12\x18$0H`l\x03\x01\x080\x18\x01\x00\x00\x0f\xac\x04\x02\x00\x00\x0f\xac\x04\x00\x0f\xac\x02\x01\x00\x00\x0f\xac\x02\x0c\x00'
    pkt = RadioTap(data)
    nstats = pkt[Dot11Beacon].network_stats()
    assert nstats == {
       'channel': 8,
       'crypto': {'WPA2'},
       'rates': [130, 132, 12, 18, 24, 36, 48, 72, 96, 108],
       'ssid': 'SSID76'
    }
    

    It is only available in the Dot11Beacon, as it’s the only place where it really makes sense so you have to call it specifically on this layer (you need to check the layer is set on a packet first)