def _process_eapol_frame(self, request): eapol_frames = [] # 1. Check EAPOL type if request[EAPOL].type == EAPOL.EAP_PACKET: # Process EAP packet eap_packet = self._eap_handler.process_eap_packet(request[EAP]) if eap_packet: resp = EAPOL(version=request[EAPOL].version, type=0) / eap_packet eapol_frames.append(resp) # If the EAP response contains a TLS Alert, add an EAPOL-Logoff # frame to the frames that are to be sent. tls_data = get_tls_data(eap_packet) if tls_data: if tls_data.msg and isinstance(tls_data.msg[0], TLSAlert): eapol_frames.append(EAPOL(version=resp.version, type=2)) else: # After having received an EAP-Failure or an EAP-Request # matching the current authentication method, send a Logoff # message. eapol_frames.append( EAPOL(version=request[EAPOL].version, type=2)) return eapol_frames
def stop(self): """ Stop listening, free resources. """ # Send an EAPOL-Logoff frame eapol_logoff_frame = EAPOL(version=self._eapol_version, type=2) self.send_frame(eapol_logoff_frame) if self._association_status != \ WiFiTrafficHandler.ASSO_STATUS_NOT_ASSOCIATED and \ self._bssid: self._disassociate() if self._socket: self._socket.close() if self._monitor_socket: self._monitor_socket.close() # Set interface operational state to "DOWN", and linkmode to default set_interface_operstate( self._iface_index, 0, "UP" ) self._running = False
def start(self): """ Start listening for incoming frames. """ resume_scanning = True self._running = True try: self._socket = L2ListenSocket(iface=self._iface) except OSError as err: g_default_logger.error( "Cannot listen on the provided interface \ (%s).", self._iface) g_exception_logger.exception(err) while self._running: try: read, _, __ = select.select([self._socket], [], [], 0.05) if read: frame = self._socket.recv() if frame.src != self._local_mac_addr: self._handle_received_frame(frame) if resume_scanning: # Send an EAPOL-Start frame to try to start the authentication # process. eapol_start_frame = EAPOL(version=self._eapol_version, type=1) self.send_frame(eapol_start_frame) resume_scanning = False except socket.error as err_mess: g_exception_logger.exception(err_mess) self._running = False except KeyboardInterrupt as keyboard_interrupt: # This exception should be caught (ra.py) raise keyboard_interrupt
def build_EAPOL_Key_8021X2004( key_information, replay_counter, nonce, data=None, key_mic=None, key_data_encrypt=None, key_rsc=0, key_id=0, key_descriptor_type=2, # EAPOL RSN Key ): pkt = EAPOL(version="802.1X-2004", type="EAPOL-Key") key_iv = KrackAP.gen_nonce(16) assert key_rsc == 0 # Other values unsupported assert key_id == 0 # Other values unsupported payload = b"".join([ chb(key_descriptor_type), struct.pack(">H", key_information), b'\x00\x20', # Key length struct.pack(">Q", replay_counter), nonce, key_iv, struct.pack(">Q", key_rsc), struct.pack(">Q", key_id), ]) # MIC field is set to 0's during MIC computation offset_MIC = len(payload) payload += b'\x00' * 0x10 if data is None and key_mic is None and key_data_encrypt is None: # If key is unknown and there is no data, no MIC is needed # Exemple: handshake 1/4 payload += b'\x00' * 2 # Length return pkt / Raw(load=payload) assert data is not None assert key_mic is not None assert key_data_encrypt is not None # Skip 256 first bytes # REF: 802.11i 8.5.2 # Key Descriptor Version 1: # ... # No padding shall be used. The encryption key is generated by # concatenating the EAPOL-Key IV field and the KEK. The first 256 octets # of the RC4 key stream shall be discarded following RC4 stream cipher # initialization with the KEK, and encryption begins using the 257th key # stream octet. enc_data = ARC4_encrypt(key_iv + key_data_encrypt, data, skip=256) payload += struct.pack(">H", len(data)) payload += enc_data # Compute MIC and set at the right place temp_mic = pkt.copy() temp_mic /= Raw(load=payload) to_mic = raw(temp_mic[EAPOL]) mic = hmac.new(key_mic, to_mic, hashlib.md5).digest() final_payload = payload[:offset_MIC] + mic + payload[offset_MIC + len(mic):] assert len(final_payload) == len(payload) return pkt / Raw(load=final_payload)
def _handle_received_frame(self, frame): """ If a frame carrying an EAP packet has been received, add it to the queue and notify the observers. Handle 802.11 authentication and association. """ # # 802.11 # dot11_frame = frame[Dot11] # Is it a Probe Response ? if frame[Dot11].type == 0b00 and frame[Dot11].subtype == 5: if self._authentication_status == \ WiFiTrafficHandler.AUTH_STATUS_AUTHENTICATED: # If we're already authenticated, there is no need to process # a Probe Response. return # Look for the SSID if Dot11Elt in frame[Dot11]: data = frame[Dot11][Dot11Elt] ssid_found = self._parse_ies(data) if ssid_found and self._authentication_status == \ WiFiTrafficHandler.AUTH_STATUS_NOT_AUTHENTICATED: if not self._authentication_status == \ WiFiTrafficHandler.AUTH_STATUS_AUTHENTICATING: # Attempt to authenticate self._authentication_status = \ WiFiTrafficHandler.AUTH_STATUS_AUTHENTICATING if self._authenticate(): # At this point, the authentication process probably # failed g_default_logger.warning("Could not authenticate.") self._authentication_status = \ WiFiTrafficHandler.AUTH_STATUS_NOT_AUTHENTICATED # Is it a Deauthentication frame ? elif Dot11Deauth in dot11_frame: g_default_logger.warning("Deauthenticated.\tBSSID: %s", self._bssid) self._authentication_status = \ WiFiTrafficHandler.AUTH_STATUS_NOT_AUTHENTICATED elif Dot11Disas in dot11_frame: g_default_logger.warning( "Disassociated.\tSSID: %s, BSSID: %s", self._ssid, self._bssid ) self._association_status = \ WiFiTrafficHandler.ASSO_STATUS_NOT_ASSOCIATED # Consider we're not authenticated anymore, as well self._authentication_status = \ WiFiTrafficHandler.AUTH_STATUS_NOT_AUTHENTICATED self._clear_ssid_info() elif Dot11Auth in dot11_frame: if self._authentication_status == \ WiFiTrafficHandler.AUTH_STATUS_AUTHENTICATING: if dot11_frame.algo == 0 and dot11_frame.status == 0: g_default_logger.info( "Authenticated.\tBSSID: %s", self._bssid ) self._authentication_status = \ WiFiTrafficHandler.AUTH_STATUS_AUTHENTICATED # Attempt to associate self._association_status =\ WiFiTrafficHandler.ASSO_STATUS_ASSOCIATING if self._associate(): # At this point, the association process probably # failed g_default_logger.warning( "Could not associate with %s", self._bssid ) self._association_status = \ WiFiTrafficHandler.ASSO_STATUS_NOT_ASSOCIATED elif Dot11AssoResp in dot11_frame: if dot11_frame.status == 0: # The association succeeded g_default_logger.info( "Associated.\tSSID: %s, BSSID: %s", self._ssid, self._bssid ) self._association_status = \ WiFiTrafficHandler.ASSO_STATUS_ASSOCIATED self._previously_associated = True # Resume the scanning process, if it was interrupted eapol_start_frame = EAPOL(version=self._eapol_version, type=1) self.send_frame(eapol_start_frame) # # EAPOL / EAP # elif EAPOL in frame: if EAP in frame: g_traffic_logger.info("\t<- %s", frame[EAP].summary()) try: self._received_frames.put(frame, block=False) except queue.Full: # The authentication process is made of ordered request / # response exchanges. This should not happen ... while not self._received_frames.empty(): self._received_frames.get() self._received_frames.put(frame, block=False) event = common.FrameReceivedEvent() self.notify_observers(event) # Use the same EAPOL version self._eapol_version = frame[EAPOL].version
def check_eap_type(self, essid, eaptype, outer_identity='user', eapol_start=False, rsnInfo=''): """ Check that an eaptype is supported. errDict = { 0:"supported", 1:"not supported", 2:"could not determine", 3:"identity rejected" } """ eapid = randint(1, 254) if eapol_start: eapol_start_request = ( RadioTap()/ Dot11(FCfield=0x01, addr1=self.bssid, addr2=self.source_mac, addr3=self.bssid, SC=self.__fixSC__(), type=2, subtype=8)/ Dot11QoS()/ LLC(dsap=170, ssap=170, ctrl=3)/ SNAP(code=0x888e)/ EAPOL(version=1, type=1) ) self.sequence += 1 i = 0 for i in range(0, EAP_MAX_TRIES): self.__thread_sendp__(eapol_start_request) if not self.lastpacket is None: if self.lastpacket.haslayer('EAP'): fields = self.lastpacket.getlayer('EAP').fields if 'type' in fields and fields['type'] == 1 and fields['code'] == 1: i = 0 eapid = fields['id'] break if i == 2: return 2 eap_identity_response = ( RadioTap()/ Dot11(FCfield=0x01, addr1=self.bssid, addr2=self.source_mac, addr3=self.bssid, SC=self.__fixSC__(), type=2, subtype=8)/ Dot11QoS()/ LLC(dsap=170, ssap=170, ctrl=3)/ SNAP(code=0x888e)/ EAPOL(version=1, type=0)/ EAP(code=2, type=1, id=eapid, identity=outer_identity) ) eap_legacy_nak = ( RadioTap()/ Dot11(FCfield=0x01, addr1=self.bssid, addr2=self.source_mac, addr3=self.bssid, SC=self.__fixSC__(), type=2, subtype=8)/ Dot11QoS()/ LLC(dsap=170, ssap=170, ctrl=3)/ SNAP(code=0x888e)/ EAPOL(version=1, type=0, len=6)/ EAP(code=2, type=3, id=eapid + 1, eap_types=[eaptype]) ) self.sequence += 1 for i in range(0, EAP_MAX_TRIES): self.__thread_sendp__(eap_identity_response) if not self.lastpacket is None: if self.lastpacket.haslayer('EAP'): fields = self.lastpacket.getlayer('EAP').fields if fields['code'] == 4: # 4 is a failure return 3 if 'type' in fields and fields['type'] == eaptype: return 0 i = 0 break if i == 2: return 2 for i in range(0, EAP_MAX_TRIES): self.__thread_sendp__(eap_legacy_nak) if not self.lastpacket is None: if self.lastpacket.haslayer('EAP'): fields = self.lastpacket.getlayer('EAP').fields if 'type' in fields and fields['type'] == eaptype: return 0 else: return 1 return 2