diff --git a/research/fragattack.py b/research/fragattack.py index 6091f4e64..6ba21132e 100755 --- a/research/fragattack.py +++ b/research/fragattack.py @@ -5,7 +5,8 @@ # See README for more details. # Note that tests_*.py files are imported automatically -import glob, importlib, argparse +import glob, importlib, argparse, warnings +warnings.filterwarnings("ignore", category=DeprecationWarning) from fraginternals import * # ----------------------------------- Main Function ----------------------------------- @@ -90,8 +91,7 @@ def prepare_tests(opt): elif opt.testname in ["eapol-amsdu", "eapol-amsdu-bad"]: freebsd = opt.testname.endswith("-bad") actions = str2actions(stractions, - [Action(Action.StartAuth, enc=False), - Action(Action.StartAuth, enc=False)]) + [Action(Action.StartAuth, enc=False)]) test = EapolAmsduTest(REQ_ICMP, actions, freebsd, opt) elif opt.testname == "linux-plain": diff --git a/research/fraginternals.py b/research/fraginternals.py index 09d054ecd..bd1962fdf 100644 --- a/research/fraginternals.py +++ b/research/fraginternals.py @@ -8,8 +8,57 @@ import abc, sys, socket, struct, time, subprocess, atexit, select, copy import os.path from wpaspy import Ctrl -from scapy.contrib.wpa_eapol import WPA_key -from scapy.arch.common import get_if_raw_hwaddr +try: + from scapy.contrib.wpa_eapol import WPA_key + def _eapol_key_info(pkt): + return pkt[WPA_key].key_info +except ImportError: + # Scapy 2.5+ removed scapy.contrib.wpa_eapol; EAPOL key handling is + # now in scapy.layers.eap as EAPOL_KEY with individual bit fields. + from scapy.layers.eap import EAPOL_KEY as WPA_key + def _eapol_key_info(pkt): + ek = pkt[WPA_key] + return (ek.key_descriptor_type_version | + (ek.key_type << 3) | + (ek.install << 6) | + (ek.key_ack << 7) | + (ek.has_key_mic << 8) | + (ek.secure << 9) | + (ek.error << 10) | + (ek.request << 11) | + (ek.encrypted_key_data << 12) | + (ek.smk_message << 13)) +try: + from scapy.arch.common import get_if_raw_hwaddr +except ImportError: + try: + from scapy.arch import get_if_raw_hwaddr + except ImportError: + # Scapy 2.7+ removed get_if_raw_hwaddr on Linux; implement via ioctl + import socket as _socket, struct as _struct, fcntl as _fcntl + def get_if_raw_hwaddr(iface): + SIOCGIFHWADDR = 0x8927 + s = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM, 0) + try: + d = _struct.pack('256s', iface[:15].encode()) + res = _fcntl.ioctl(s.fileno(), SIOCGIFHWADDR, d) + return _struct.unpack_from('H6s', res, 16) + finally: + s.close() + +# scapy.arch.get_if_index was removed in Scapy 2.7; patch it back in via ioctl +if not hasattr(scapy.arch, 'get_if_index'): + import fcntl as _fcntl + def _get_if_index(iface): + SIOCGIFINDEX = 0x8933 + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) + try: + d = struct.pack('256s', iface[:15].encode()) + res = _fcntl.ioctl(s.fileno(), SIOCGIFINDEX, d) + return struct.unpack_from('I', res, 16)[0] + finally: + s.close() + scapy.arch.get_if_index = _get_if_index FRAGVERSION = "1.3" @@ -492,11 +541,12 @@ def trigger_eapol_events(self, eapol): # Track return value of possible trigger Action function result = None - key_type = eapol.key_info & 0x0008 - key_ack = eapol.key_info & 0x0080 - key_mic = eapol.key_info & 0x0100 - key_secure = eapol.key_info & 0x0200 - key_request = eapol.key_info & 0x0800 + key_info = _eapol_key_info(eapol) + key_type = key_info & 0x0008 + key_ack = key_info & 0x0080 + key_mic = key_info & 0x0100 + key_secure = key_info & 0x0200 + key_request = key_info & 0x0800 # Detect Msg3/4 assumig WPA2 is used --- XXX support WPA1 as well is_msg3_or_4 = key_secure != 0 @@ -537,7 +587,7 @@ def handle_eapol_tx(self, eapol, dstmac): # - Some routers such as the RT-AC51U do the 4-way rekey HS in plaintext. plaintext = self.options.rekey_plaintext - if WPA_key in eapol and eapol[WPA_key].key_info & 2048: + if WPA_key in eapol and _eapol_key_info(eapol) & 0x0800: plaintext = False self.send_mon(eapol, plaintext=plaintext) @@ -779,7 +829,17 @@ def configure_interfaces(self): scapy.arch.get_if_index(self.nic_mon) except IOError: subprocess.call(["iw", self.nic_mon, "del"], stdout=subprocess.PIPE, stdin=subprocess.PIPE) - subprocess.check_output(["iw", self.nic_iface, "interface", "add", self.nic_mon, "type", "monitor"]) + try: + subprocess.check_output(["iw", self.nic_iface, "interface", "add", self.nic_mon, "type", "monitor"], + stderr=subprocess.PIPE) + except subprocess.CalledProcessError as ex: + log(ERROR, "Failed to create virtual monitor interface {}: {}".format(self.nic_mon, ex.stderr.decode().strip())) + log(ERROR, "Try using --inject {} to skip virtual interface creation.".format(self.nic_iface)) + quit(1) + # Give the kernel time to initialise the new virtual interface before use. + # Some drivers (e.g. mt76) crash with a null-pointer dereference if we + # open a socket on the interface immediately after iw returns. + time.sleep(0.5) # 2.A Remember whether to need to use injection workarounds. driver = get_device_driver(self.nic_mon) @@ -1242,7 +1302,7 @@ def handle_wpaspy(self, msg): # When using a separate interface to inject, switch to correct channel self.follow_channel() - p = re.compile("Associated with (.*)") + p = re.compile(r"Associated with (.*)") bss = p.search(msg).group(1) self.station.handle_connecting(bss) diff --git a/research/libwifi/wifi.py b/research/libwifi/wifi.py index 3bd229b21..416240cda 100644 --- a/research/libwifi/wifi.py +++ b/research/libwifi/wifi.py @@ -3,10 +3,30 @@ # This code may be distributed under the terms of the BSD license. # See README for more details. from scapy.all import * +from scapy.arch import L2Socket, attach_filter from Crypto.Cipher import AES from datetime import datetime import binascii +# get_if_raw_hwaddr was removed in Scapy 2.7; provide ioctl fallback for Linux +if 'get_if_raw_hwaddr' not in dir(): + try: + from scapy.arch.common import get_if_raw_hwaddr + except ImportError: + try: + from scapy.arch import get_if_raw_hwaddr + except ImportError: + import socket as _socket, struct as _struct, fcntl as _fcntl + def get_if_raw_hwaddr(iface): + SIOCGIFHWADDR = 0x8927 + s = _socket.socket(_socket.AF_INET, _socket.SOCK_DGRAM, 0) + try: + d = _struct.pack('256s', iface[:15].encode()) + res = _fcntl.ioctl(s.fileno(), SIOCGIFHWADDR, d) + return _struct.unpack_from('H6s', res, 16) + finally: + s.close() + #### Constants #### FRAME_TYPE_MANAGEMENT = 0 @@ -102,7 +122,7 @@ def addr2bin(addr): def get_channel(iface): output = str(subprocess.check_output(["iw", iface, "info"])) - p = re.compile("channel (\d+)") + p = re.compile(r"channel (\d+)") m = p.search(output) if m == None: return None return int(m.group(1)) @@ -123,7 +143,7 @@ def set_macaddress(iface, macaddr): def get_iface_type(iface): output = str(subprocess.check_output(["iw", iface, "info"])) - p = re.compile("type (\w+)") + p = re.compile(r"type (\w+)") return str(p.search(output).group(1)) def set_monitor_mode(iface, up=True, mtu=1500): @@ -220,9 +240,12 @@ def print_reply(self, req, reply): #### Packet Processing Functions #### -# Compatibility with older Scapy versions -if not "ORDER" in scapy.layers.dot11._rt_txflags: - scapy.layers.dot11._rt_txflags.append("ORDER") +# Compatibility with older Scapy versions — _rt_txflags may not exist or already contain ORDER +try: + if "ORDER" not in scapy.layers.dot11._rt_txflags: + scapy.layers.dot11._rt_txflags.append("ORDER") +except AttributeError: + pass class MonitorSocket(L2Socket): def __init__(self, iface, dumpfile=None, detect_injected=False, **kwargs): @@ -384,7 +407,7 @@ def get_ccmp_payload(p): # Extract encrypted payload: # - Skip extended IV (4 bytes in total) # - Exclude first 4 bytes of the CCMP MIC (note that last 4 are saved in the WEP ICV field) - return str(p.wepdata[4:-4]) + return bytes(p.wepdata[4:-4]) elif Dot11CCMP in p: return p[Dot11CCMP].data elif Dot11TKIP in p: @@ -484,7 +507,7 @@ def create_msdu_subframe(src, dst, payload, last=False): payload = raw(payload) total_length = len(p) + len(payload) - padding = "" + padding = b"" if not last and total_length % 4 != 0: padding = b"\x00" * (4 - (total_length % 4)) diff --git a/research/pysetup.sh b/research/pysetup.sh index decca233d..13c5d2ec3 100755 --- a/research/pysetup.sh +++ b/research/pysetup.sh @@ -9,6 +9,10 @@ source venv/bin/activate pip install wheel pip install -r requirements.txt -# Fix a bug in scapy that isn't fixed in the PyPI version yet. For background see +# Fix a bug in scapy<=2.4.3 that isn't fixed in the PyPI version yet. For background see # https://github.com/secdev/scapy/commit/46fa40fde4049ad7770481f8806c59640df24059 -sed -i 's/find_library("libc")/find_library("c")/g' venv/lib/python*/site-packages/scapy/arch/bpf/core.py +# (no-op on scapy>=2.4.4 where this was already fixed upstream) +BPF_CORE="venv/lib/python*/site-packages/scapy/arch/bpf/core.py" +for f in $BPF_CORE; do + [ -f "$f" ] && sed -i 's/find_library("libc")/find_library("c")/g' "$f" +done diff --git a/research/requirements.txt b/research/requirements.txt index 9551abc2e..6f9dabf37 100644 --- a/research/requirements.txt +++ b/research/requirements.txt @@ -1,16 +1,11 @@ -attrs==19.3.0 -importlib-metadata==1.5.0 -more-itertools==8.2.0 -mpmath==1.1.0 -packaging==20.1 -pluggy==0.13.1 -py==1.10.0 -pycryptodome==3.9.7 -pyparsing==2.4.6 -pytest==5.3.5 -scapy==2.4.3 -simpy==3.0.11 -six==1.14.0 -sympy==1.5.1 -wcwidth==0.1.8 -zipp==3.0.0 +attrs>=21.0.0 +mpmath>=1.2.0 +packaging>=21.0 +pluggy>=1.0.0 +pycryptodome>=3.9.7 +pyparsing>=3.0.0 +pytest>=7.0.0 +scapy>=2.5.0 +simpy>=4.0.0 +six>=1.16.0 +sympy>=1.9.0 diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index 4a54ab0e5..8ae79e493 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -23,6 +23,9 @@ #include #include #endif /* CONFIG_ECC */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif /* OpenSSL version >= 3.0 */ #include "common.h" #include "utils/const_time.h"