def check_arp_reply(self, pkt): data = parse_data_pkt(pkt, self.tk) try: data_clear = check_MIC_ICV(data, self.mic_sta_to_ap, pkt.addr2, pkt.addr3) except (ICVError, MICError): return decoded_pkt = LLC(data_clear) log_runtime.debug(hexdump(decoded_pkt, dump=True)) log_runtime.debug(repr(decoded_pkt)) self.deal_common_pkt(decoded_pkt) if ARP not in decoded_pkt: return # ARP.op 2: is-at if decoded_pkt[ARP].op == 2 and \ decoded_pkt[ARP].psrc == self.arp_target_ip and \ decoded_pkt[ARP].pdst == self.arp_source_ip: # Got the expected ARP if self.krack_state & 4 == 0: # First time, normal behavior log_runtime.info("Got ARP reply, this is normal") self.krack_state |= 4 log_runtime.info("Trying to trigger CVE-2017-13080") raise self.RENEW_GTK() else: # Second time, the packet has been accepted twice! log_runtime.warning("Broadcast packet accepted twice!! " "(CVE-2017-13080)")
def debug_repr(self, name, secret): if conf.debug_tls and secret: log_runtime.debug("TLS: %s %s %s: %s", self.connection_end, self.row, name, repr_hex(secret))
def _wait(cls, handle): # type: (Optional[TimeoutScheduler.Handle]) -> None """Waits until it is time to execute the provided handle, or until another thread calls _event.set()""" now = cls._time() # Check how much time until the next timeout if handle is None: to_wait = cls.GRACE else: to_wait = handle._when - now # Wait until the next timeout, # or until event.set() gets called in another thread. if to_wait > 0: log_runtime.debug( "TimeoutScheduler Thread going to sleep @ %f " + "for %fs", now, to_wait) interrupted = cls._event.wait(to_wait) new = cls._time() log_runtime.debug( "TimeoutScheduler Thread awake @ %f, slept for" + " %f, interrupted=%d", new, new - now, interrupted) # Clear the event so that we can wait on it again, # Must be done before doing the callbacks to avoid losing a set(). cls._event.clear()
def _task(cls): # type: () -> None """Executed in a background thread, this thread will automatically start when the first timeout is added and stop when the last timeout is removed or executed.""" log_runtime.debug("TimeoutScheduler Thread spawning @ %f", cls._time()) time_empty = None try: while 1: handle = cls._peek_next() if handle is None: now = cls._time() if time_empty is None: time_empty = now # 100 ms of grace time before killing the thread if cls.GRACE < now - time_empty: return else: time_empty = None cls._wait(handle) cls._poll() finally: # Worst case scenario: if this thread dies, the next scheduled # timeout will start a new one log_runtime.debug("TimeoutScheduler Thread died @ %f", cls._time()) cls._thread = None
def _recv_fc(self, data): # type: (bytes) -> None """Process a received 'Flow Control' frame""" log_runtime.debug("Processing FC") if (self.tx_state != ISOTP_WAIT_FC and self.tx_state != ISOTP_WAIT_FIRST_FC): return if self.tx_timeout_handle is not None: self.tx_timeout_handle.cancel() self.tx_timeout_handle = None if len(data) < 3: self.tx_state = ISOTP_IDLE warning("CF frame discarded because it was too short") return # get communication parameters only from the first FC frame if self.tx_state == ISOTP_WAIT_FIRST_FC: self.txfc_bs = six.indexbytes(data, 1) self.txfc_stmin = six.indexbytes(data, 2) if ((self.txfc_stmin > 0x7F) and ((self.txfc_stmin < 0xF1) or (self.txfc_stmin > 0xF9))): self.txfc_stmin = 0x7F if six.indexbytes(data, 2) <= 127: tx_gap = six.indexbytes(data, 2) / 1000.0 elif 0xf1 <= six.indexbytes(data, 2) <= 0xf9: tx_gap = (six.indexbytes(data, 2) & 0x0f) / 10000.0 else: tx_gap = 0 self.tx_gap = tx_gap self.tx_state = ISOTP_WAIT_FC isotp_fc = six.indexbytes(data, 0) & 0x0f if isotp_fc == ISOTP_FC_CTS: self.tx_bs = 0 self.tx_state = ISOTP_SENDING # start cyclic timer for sending CF frame self.tx_timeout_handle = TimeoutScheduler.schedule( self.tx_gap, self._tx_timer_handler) elif isotp_fc == ISOTP_FC_WT: # start timer to wait for next FC frame self.tx_state = ISOTP_WAIT_FC self.tx_timeout_handle = TimeoutScheduler.schedule( self.fc_timeout, self._tx_timer_handler) elif isotp_fc == ISOTP_FC_OVFLW: # overflow in receiver side self.tx_state = ISOTP_IDLE warning("Overflow happened at the receiver side") return else: self.tx_state = ISOTP_IDLE warning("Unknown FC frame type") return
def start(self): if self.thread_lock.acquire(0): _t = Thread(target=self.run) _t.setDaemon(True) _t.start() self.thread = _t else: log_runtime.debug("Pipe engine already running")
def start(self): if self.thread_lock.acquire(0): _t = Thread(target=self.run, name="scapy.pipetool.PipeEngine") _t.daemon = True _t.start() self.thread = _t else: log_runtime.debug("Pipe engine already running")
def _recv_ff(self, data, ts): # type: (bytes, Union[float, EDecimal]) -> None """Process a received 'First Frame' frame""" log_runtime.debug("Processing FF") if self.rx_timeout_handle is not None: self.rx_timeout_handle.cancel() self.rx_timeout_handle = None if self.rx_state != ISOTP_IDLE: if conf.verb > 2: warning("RX state was reset because first frame was received") self.rx_state = ISOTP_IDLE if len(data) < 7: return self.rx_ll_dl = len(data) # get the FF_DL self.rx_len = (six.indexbytes(data, 0) & 0x0f) * 256 + six.indexbytes( data, 1) ff_pci_sz = 2 # Check for FF_DL escape sequence supporting 32 bit PDU length if self.rx_len == 0: # FF_DL = 0 => get real length from next 4 bytes self.rx_len = six.indexbytes(data, 2) << 24 self.rx_len += six.indexbytes(data, 3) << 16 self.rx_len += six.indexbytes(data, 4) << 8 self.rx_len += six.indexbytes(data, 5) ff_pci_sz = 6 # copy the first received data bytes data_bytes = data[ff_pci_sz:] self.rx_idx = len(data_bytes) self.rx_buf = data_bytes self.rx_ts = ts # initial setup for this pdu reception self.rx_sn = 1 self.rx_state = ISOTP_WAIT_DATA # no creation of flow control frames if not self.listen_only: # send our first FC frame load = self.ea_hdr load += struct.pack("BBB", N_PCI_FC, self.rxfc_bs, self.rxfc_stmin) self.can_send(load) # wait for a CF self.rx_bs = 0 self.rx_timeout_handle = TimeoutScheduler.schedule( self.cf_timeout, self._rx_timer_handler)
def compute_master_secret(self): if self.pre_master_secret is None: warning("Missing pre_master_secret while computing master_secret!") if self.client_random is None: warning("Missing client_random while computing master_secret!") if self.server_random is None: warning("Missing server_random while computing master_secret!") ms = self.pwcs.prf.compute_master_secret(self.pre_master_secret, self.client_random, self.server_random) self.master_secret = ms if conf.debug_tls: log_runtime.debug("TLS: master secret: %s", repr_hex(ms))
def stop(self, _cmd="X"): try: with self.command_lock: if self.thread is not None: self._write_cmd(_cmd) self.thread.join() try: self.thread_lock.release() except Exception: pass else: log_runtime.debug("Pipe engine thread not running") except KeyboardInterrupt: print("Interrupted by user.")
def compute_sslv2_key_material(self): if self.master_secret is None: warning("Missing master_secret while computing key_material!") if self.sslv2_challenge is None: warning("Missing challenge while computing key_material!") if self.sslv2_connection_id is None: warning("Missing connection_id while computing key_material!") km = self.pwcs.prf.derive_key_block(self.master_secret, self.sslv2_challenge, self.sslv2_connection_id, 2 * self.pwcs.cipher.key_len) self.sslv2_key_material = km if conf.debug_tls: log_runtime.debug("TLS: master secret: %s", repr_hex(self.master_secret)) # noqa: E501 log_runtime.debug("TLS: key material: %s", repr_hex(km))
def compute_sslv2_key_material(self): if self.master_secret is None: warning("Missing master_secret while computing key_material!") if self.sslv2_challenge is None: warning("Missing challenge while computing key_material!") if self.sslv2_connection_id is None: warning("Missing connection_id while computing key_material!") km = self.pwcs.prf.derive_key_block(self.master_secret, self.sslv2_challenge, self.sslv2_connection_id, 2*self.pwcs.cipher.key_len) self.sslv2_key_material = km if conf.debug_tls: log_runtime.debug("TLS: master secret: %s", repr_hex(self.master_secret)) log_runtime.debug("TLS: key material: %s", repr_hex(km))
def run(self): # type: () -> None log_runtime.debug("Pipe engine thread started.") try: for p in self.active_pipes: p.start() sources = self.active_sources sources.add(self) exhausted = set([]) # type: Set[Union[Source, PipeEngine]] RUN = True STOP_IF_EXHAUSTED = False while RUN and (not STOP_IF_EXHAUSTED or len(sources) > 1): fds = select_objects(sources, 0.5) for fd in fds: if fd is self: cmd = self._read_cmd() if cmd == "X": RUN = False break elif cmd == "B": STOP_IF_EXHAUSTED = True elif cmd == "A": sources = self.active_sources - exhausted sources.add(self) else: warning( "Unknown internal pipe engine command: %r." " Ignoring.", cmd) elif fd in sources: try: fd.deliver() except Exception as e: log_runtime.exception("piping from %s failed: %s", fd.name, e) else: if fd.exhausted(): exhausted.add(fd) sources.remove(fd) except KeyboardInterrupt: pass finally: try: for p in self.active_pipes: p.stop() finally: self.thread_lock.release() log_runtime.debug("Pipe engine thread stopped.")
def test_and_setup_socket_can(iface_name): # type: (str) -> None if 0 != subprocess.call(("cansend %s 000#" % iface_name).split()): # iface_name is not enabled if 0 != subprocess.call("modprobe vcan".split()): raise Exception("modprobe vcan failed") if 0 != subprocess.call( ("ip link add name %s type vcan" % iface_name).split()): log_runtime.debug("add %s failed: Maybe it was already up?" % iface_name) if 0 != subprocess.call( ("ip link set dev %s up" % iface_name).split()): raise Exception("could not bring up %s" % iface_name) if 0 != subprocess.call(("cansend %s 000#12" % iface_name).split()): raise Exception("cansend doesn't work") sys.__stderr__.write("SocketCAN setup done!\n")
def _recv_sf(self, data, ts): # type: (bytes, Union[float, EDecimal]) -> None """Process a received 'Single Frame' frame""" log_runtime.debug("Processing SF") if self.rx_timeout_handle is not None: self.rx_timeout_handle.cancel() self.rx_timeout_handle = None if self.rx_state != ISOTP_IDLE: if conf.verb > 2: warning("RX state was reset because single frame was received") self.rx_state = ISOTP_IDLE length = six.indexbytes(data, 0) & 0xf if len(data) - 1 < length: return msg = data[1:1 + length] self.rx_queue.send((msg, ts))
def extract_iv(self, pkt): # Get IV TSC, _, _ = parse_TKIP_hdr(pkt) iv = TSC[0] | (TSC[1] << 8) | (TSC[2] << 16) | (TSC[3] << 24) | \ (TSC[4] << 32) | (TSC[5] << 40) log_runtime.info("Got a packet with IV: %s", hex(iv)) if self.last_iv is None: self.last_iv = iv else: if iv <= self.last_iv: log_runtime.warning("IV re-use!! Client seems to be " "vulnerable to handshake 3/4 replay " "(CVE-2017-13077)" ) data_clear = None # Normal decoding data = parse_data_pkt(pkt, self.tk) try: data_clear = check_MIC_ICV(data, self.mic_sta_to_ap, pkt.addr2, pkt.addr3) except (ICVError, MICError): pass # Decoding with a 0's TK if data_clear is None: data = parse_data_pkt(pkt, "\x00" * len(self.tk)) try: mic_key = "\x00" * len(self.mic_sta_to_ap) data_clear = check_MIC_ICV(data, mic_key, pkt.addr2, pkt.addr3) log_runtime.warning("Client has installed an all zero " "encryption key (TK)!!") except (ICVError, MICError): pass if data_clear is None: log_runtime.warning("Unable to decode the packet, something went " "wrong") log_runtime.debug(hexdump(pkt, dump=True)) self.deal_common_pkt(pkt) return log_runtime.debug(hexdump(data_clear, dump=True)) pkt = LLC(data_clear) log_runtime.debug(repr(pkt)) self.deal_common_pkt(pkt)
iface_name) if 0 != subprocess.call( ("ip link set dev %s up" % iface_name).split()): raise Exception("could not bring up %s" % iface_name) if 0 != subprocess.call(("cansend %s 000#12" % iface_name).split()): raise Exception("cansend doesn't work") sys.__stderr__.write("SocketCAN setup done!\n") if LINUX and _root and _not_pypy: try: test_and_setup_socket_can(iface0) test_and_setup_socket_can(iface1) log_runtime.debug("CAN should work now") _socket_can_support = True except Exception as e: sys.__stderr__.write("ERROR %s!\n" % e) sys.__stderr__.write("SocketCAN support: %s\n" % _socket_can_support) # ############################################################################ # """ Define helper functions for CANSocket creation on all platforms """ # ############################################################################ if _socket_can_support: if six.PY3: from scapy.contrib.cansocket_native import * # noqa: F403 new_can_socket = NativeCANSocket new_can_socket0 = lambda: NativeCANSocket(iface0) new_can_socket1 = lambda: NativeCANSocket(iface1)
def RENEW_GTK(self): log_runtime.debug("State RENEW_GTK")
def ANALYZE_DATA(self): log_runtime.debug("State ANALYZE_DATA")
def send_beacon(self): log_runtime.debug("Send a beacon") rep = self.build_ap_info_pkt(Dot11Beacon, dest="ff:ff:ff:ff:ff:ff") self.send(rep)
def WAIT_GTK_ACCEPT(self): log_runtime.debug("State WAIT_GTK_ACCEPT")
def ASSOC_RESPONSE_SENT(self): log_runtime.debug("State ASSOC_RESPONSE_SENT")
def EXIT(self): log_runtime.debug("State EXIT")
def debug(self, lvl, msg): # type: (int, str) -> None if self.debug_level >= lvl: log_runtime.debug(msg)
def KRACK_DISPATCHER(self): log_runtime.debug("State KRACK_DISPATCHER")
def WPA_HANDSHAKE_STEP_3_SENT(self): log_runtime.debug("State WPA_HANDSHAKE_STEP_3_SENT")
def AUTH_RESPONSE_SENT(self): log_runtime.debug("State AUTH_RESPONSE_SENT")
def WAIT_ARP_REPLIES(self): log_runtime.debug("State WAIT_ARP_REPLIES")
def _recv_cf(self, data): # type: (bytes) -> None """Process a received 'Consecutive Frame' frame""" log_runtime.debug("Processing CF") if self.rx_state != ISOTP_WAIT_DATA: return if self.rx_timeout_handle is not None: self.rx_timeout_handle.cancel() self.rx_timeout_handle = None # CFs are never longer than the FF if len(data) > self.rx_ll_dl: return # CFs have usually the LL_DL length if len(data) < self.rx_ll_dl: # this is only allowed for the last CF if self.rx_len - self.rx_idx > self.rx_ll_dl: if conf.verb > 2: warning("Received a CF with insufficient length") return if six.indexbytes(data, 0) & 0x0f != self.rx_sn: # Wrong sequence number if conf.verb > 2: warning("RX state was reset because wrong sequence number was " "received") self.rx_state = ISOTP_IDLE return if self.rx_buf is None: if conf.verb > 2: warning("rx_buf not filled with data!") self.rx_state = ISOTP_IDLE return self.rx_sn = (self.rx_sn + 1) % 16 self.rx_buf += data[1:] self.rx_idx = len(self.rx_buf) if self.rx_idx >= self.rx_len: # we are done self.rx_buf = self.rx_buf[0:self.rx_len] self.rx_state = ISOTP_IDLE self.rx_queue.send((self.rx_buf, self.rx_ts)) self.rx_buf = None return # perform blocksize handling, if enabled if self.rxfc_bs != 0: self.rx_bs += 1 # check if we reached the end of the block if self.rx_bs >= self.rxfc_bs and not self.listen_only: # send our FC frame load = self.ea_hdr load += struct.pack("BBB", N_PCI_FC, self.rxfc_bs, self.rxfc_stmin) self.rx_bs = 0 self.can_send(load) # wait for another CF log_runtime.debug("Wait for another CF") self.rx_timeout_handle = TimeoutScheduler.schedule( self.cf_timeout, self._rx_timer_handler)
def WAIT_AUTH_REQUEST(self): log_runtime.debug("State WAIT_AUTH_REQUEST")
def debug(self, lvl, msg): if self.debug_level >= lvl: log_runtime.debug(msg)