def _prepare(self): err = None bss_status_attr = None rsn_ie_data = None vendor_ie_data = None # Scan first try: err, bss_status_attr, rsn_ie_data, vendor_ie_data = self._scan() while err or (not rsn_ie_data and not vendor_ie_data): time.sleep(0.5) g_default_logger.info("Looking for %s ...", self._ssid) err, bss_status_attr, rsn_ie_data, vendor_ie_data = \ self._scan() except KeyboardInterrupt as keyboard_interrupt: # This exception should be caught (ra.py) raise keyboard_interrupt if bss_status_attr: if bss_status_attr == 0: # Send a Deauthentication frame self._authentication_status = \ WiFiTrafficHandler.AUTH_STATUS_NOT_AUTHENTICATED self._deauthenticate() elif bss_status_attr == 1: # Send a Disassociation frame self._association_status = \ WiFiTrafficHandler.ASSO_STATUS_NOT_ASSOCIATED self._disassociate() if rsn_ie_data: packed_ies = struct.pack("!B", 48) + \ struct.pack("!B", len(rsn_ie_data)) + rsn_ie_data info_elements = Dot11Elt(packed_ies) if Dot11EltRSN in info_elements: self._rsn = info_elements[Dot11EltRSN] if vendor_ie_data: for vendor_ie in vendor_ie_data: packed_ies = struct.pack("!B", 221) + \ struct.pack("!B", len(vendor_ie)) + vendor_ie info_element = Dot11Elt(packed_ies) if isinstance(info_element, Dot11EltMicrosoftWPA): self._ms_wpa_ie = info_element[Dot11EltMicrosoftWPA] if not self._expected_akm_found(): g_default_logger.warning( "(%s) AKM is not IEEE 802.1X / PMKSA \ caching.", self._ssid)
def send_frame(self, eapol_frame): """ Send an EAPOL frame. """ # Prevent frames from being sent once the handler has been stopped # (this may happen when ending the scanning process, when there are # still events in the stack). if not self._running: return if EAP in eapol_frame: g_traffic_logger.info("%s ->", eapol_frame[EAP].summary()) elif EAPOL in eapol_frame: g_traffic_logger.info("%s ->", eapol_frame[EAPOL].summary()) else: g_traffic_logger.info(eapol_frame.summary()) if self._bssid: dest_addr = self._bssid.replace(':', '') packed_dest_addr = binascii.unhexlify(dest_addr) self._socket.sendto( bytes(eapol_frame), (self._iface, IEEE_802_1X_ETHERTYPE, 0, 0, packed_dest_addr)) else: if EAP in eapol_frame: g_default_logger.warning("Could not send frame: %s", \ eapol_frame[EAP].summary()) elif EAPOL in eapol_frame: g_default_logger.warning("Could not send frame: %s", \ eapol_frame[EAPOL].summary()) else: g_default_logger.warning("Could not send frame: %s", \ eapol_frame.summary())
def start(self): """ Start listening for incoming frames. """ # Open a socket that will be used to send frames self._socket = socket.socket( socket.AF_PACKET, socket.SOCK_DGRAM, socket.htons(ETH_P_ALL) ) # Open a socket on the monitor interface self._monitor_socket = L2ListenSocket(iface=MONITOR_INTERFACE_NAME) i = 0 self._running = True while self._running: try: read, _, __ = select.select([self._monitor_socket.fileno()], [], [], 0.05) if read: data_ = self._monitor_socket.recv(4096) frame = RadioTap(data_) if Dot11 in frame and\ frame[Dot11].addr2 != self._local_mac_addr: self._handle_received_frame(frame) # Every 2.5+ seconds, try to detect any association loss if not i % 50: association_loss = self._detect_association_loss() if association_loss: g_default_logger.info("Not associated with %s \ anymore.", self._bssid) self._clear_ssid_info() i = 0 # If we're not associated, trigger a new scan in order to # retrieve necessary information if not self._has_ssid_info(): self._prepare() else: if self._association_status != \ WiFiTrafficHandler.ASSO_STATUS_NOT_ASSOCIATED: # Info retrieved in a Probe Response ? # If so, scan in order to get (hopefully) up-to-date # data in another Probe Response if self._previously_associated and \ self._ssid_info_learned_in_presp: self._prepare() else: if not self._authentication_status == \ WiFiTrafficHandler.AUTH_STATUS_AUTHENTICATING or \ not i % 20: if not self._authenticate(): self._authentication_status = \ WiFiTrafficHandler.AUTH_STATUS_AUTHENTICATING else: g_default_logger.warning("Could not \ authenticate") i = i + 1 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 _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