class NTLM_Client(_NTLM_Automaton): """ A class to overload to create a client automaton when using the NTLM relay. """ port = 445 cls = conf.raw_layer ssl = False kwargs_cls = {} def __init__(self, *args, **kwargs): self.client_pipe = ObjectPipe() super(NTLM_Client, self).__init__(*args, **kwargs) def bind(self, srv_atmt): # type: (NTLM_Server) -> None self.srv_atmt = srv_atmt def set_srv(self, attr, value): self.srv_atmt.values[attr] = value def get_token(self): return self.srv_atmt.token_pipe.recv() def echo(self, pkt): return self.srv_atmt.send(pkt) def wait_server(self): kwargs = self.client_pipe.recv() self.client_pipe.close() return kwargs
def __init__(self, sock, **kwargs): # type: (StreamSocket, Any) -> None self.token_pipe = ObjectPipe() self.values = {} for key, dflt in [("DROP_MIC_v1", False), ("DROP_MIC_v2", False)]: setattr(self, key, kwargs.pop(key, dflt)) self.DROP_MIC = self.DROP_MIC_v1 or self.DROP_MIC_v2 super(_NTLM_Automaton, self).__init__(recvsock=lambda **kwargs: sock, ll=lambda **kwargs: sock, **kwargs)
def __init__(self, *pipes): ObjectPipe.__init__(self) self.active_pipes = set() self.active_sources = set() self.active_drains = set() self.active_sinks = set() self._add_pipes(*pipes) self.thread_lock = Lock() self.command_lock = Lock() self.thread = None
def __init__(self, *pipes): # type: (*Pipe) -> None ObjectPipe.__init__(self, "PipeEngine") self.active_pipes = set() # type: Set[Pipe] self.active_sources = set() # type: Set[Union[Source, PipeEngine]] self.active_drains = set() # type: Set[Pipe] self.active_sinks = set() # type: Set[Pipe] self._add_pipes(*pipes) self.thread_lock = Lock() self.command_lock = Lock() self.thread = None # type: Optional[Thread]
def _run(self, count=0, store=True, offline=None, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, iface=None, started_callback=None, session=None, *arg, **karg): self.running = True # Start main thread c = 0 session = session or DefaultSession session = session(prn, store) # instantiate session # sniff_sockets follows: {socket: label} sniff_sockets = {} if opened_socket is not None: if isinstance(opened_socket, list): sniff_sockets.update( (s, "socket%d" % i) for i, s in enumerate(opened_socket)) elif isinstance(opened_socket, dict): sniff_sockets.update( (s, label) for s, label in six.iteritems(opened_socket)) else: sniff_sockets[opened_socket] = "socket0" if offline is not None: flt = karg.get('filter') from scapy.arch.common import TCPDUMP if not TCPDUMP and flt is not None: message = "tcpdump is not available. Cannot use filter!" raise Scapy_Exception(message) if isinstance(offline, list): sniff_sockets.update( (PcapReader(fname if flt is None else tcpdump( fname, args=["-w", "-", flt], getfd=True)), fname) for fname in offline) elif isinstance(offline, dict): sniff_sockets.update( (PcapReader(fname if flt is None else tcpdump( fname, args=["-w", "-", flt], getfd=True)), label) for fname, label in six.iteritems(offline)) else: sniff_sockets[PcapReader(offline if flt is None else tcpdump( offline, args=["-w", "-", flt], getfd=True))] = offline if not sniff_sockets or iface is not None: if L2socket is None: L2socket = conf.L2listen if isinstance(iface, list): sniff_sockets.update( (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), ifname) for ifname in iface) elif isinstance(iface, dict): sniff_sockets.update( (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), iflabel) for ifname, iflabel in six.iteritems(iface)) else: sniff_sockets[L2socket(type=ETH_P_ALL, iface=iface, *arg, **karg)] = iface # Get select information from the sockets _main_socket = next(iter(sniff_sockets)) read_allowed_exceptions = _main_socket.read_allowed_exceptions select_func = _main_socket.select _backup_read_func = _main_socket.__class__.recv nonblocking_socket = _main_socket.nonblocking_socket # We check that all sockets use the same select(), or raise a warning if not all(select_func == sock.select for sock in sniff_sockets): warning("Warning: inconsistent socket types ! " "The used select function " "will be the one of the first socket") # Fill if empty if not read_allowed_exceptions: read_allowed_exceptions = (IOError, ) if nonblocking_socket: # select is non blocking def stop_cb(): self.continue_sniff = False self.stop_cb = stop_cb close_pipe = None else: # select is blocking: Add special control socket from scapy.automaton import ObjectPipe close_pipe = ObjectPipe() sniff_sockets[close_pipe] = "control_socket" def stop_cb(): if self.running: close_pipe.send(None) self.continue_sniff = False self.stop_cb = stop_cb try: if started_callback: started_callback() self.continue_sniff = True # Start timeout if timeout is not None: stoptime = time.time() + timeout remain = None while sniff_sockets and self.continue_sniff: if timeout is not None: remain = stoptime - time.time() if remain <= 0: break sockets, read_func = select_func(sniff_sockets, remain) read_func = read_func or _backup_read_func dead_sockets = [] for s in sockets: if s is close_pipe: break try: p = read_func(s) except EOFError: # End of stream dead_sockets.append(s) continue except read_allowed_exceptions: continue except Exception as ex: msg = " It was closed." try: # Make sure it's closed s.close() except Exception as ex: msg = " close() failed with '%s'" % ex warning("Socket %s failed with '%s'." % (s, ex) + msg) dead_sockets.append(s) continue if p is None: continue if lfilter and not lfilter(p): continue p.sniffed_on = sniff_sockets[s] c += 1 # on_packet_received handles the prn/storage session.on_packet_received(p) # check if (stop_filter and stop_filter(p)) or (0 < count <= c): self.continue_sniff = False break # Removed dead sockets for s in dead_sockets: del sniff_sockets[s] except KeyboardInterrupt: pass self.running = False if opened_socket is None: for s in sniff_sockets: s.close() elif close_pipe: close_pipe.close() self.results = session.toPacketList()
def _exhaust(self): # type: () -> None ObjectPipe.send(self, (None, None, True))
def _gen_high_data(self, msg): # type: (str) -> None ObjectPipe.send(self, (msg, True, False))
def __init__(self, name=None): # type: (Optional[str]) -> None Pipe.__init__(self, name=name) ObjectPipe.__init__(self, name) self.is_exhausted = False
def _exhaust(self): ObjectPipe.send(self, (None, None, True))
def _gen_data(self, msg): ObjectPipe.send(self, (msg, False, False))
def __init__(self, name=None): Pipe.__init__(self, name=name) ObjectPipe.__init__(self) self.is_exhausted = False
def __init__(self, can_socket, # type: "CANSocket" src_id, # type: int dst_id, # type: int padding=False, # type: bool extended_addr=None, # type: Optional[int] extended_rx_addr=None, # type: Optional[int] rx_block_size=0, # type: int stmin=0, # type: int listen_only=False # type: bool ): # type: (...) -> None self.can_socket = can_socket self.dst_id = dst_id self.src_id = src_id self.padding = padding self.fc_timeout = 1 self.cf_timeout = 1 self.filter_warning_emitted = False self.extended_rx_addr = extended_rx_addr self.ea_hdr = b"" if extended_addr is not None: self.ea_hdr = struct.pack("B", extended_addr) self.listen_only = listen_only self.rxfc_bs = rx_block_size self.rxfc_stmin = stmin self.rx_queue = ObjectPipe() self.rx_len = -1 self.rx_buf = None # type: Optional[bytes] self.rx_sn = 0 self.rx_bs = 0 self.rx_idx = 0 self.rx_ts = 0.0 # type: Union[float, EDecimal] self.rx_state = ISOTP_IDLE self.txfc_bs = 0 self.txfc_stmin = 0 self.tx_gap = 0 self.tx_buf = None # type: Optional[bytes] self.tx_sn = 0 self.tx_bs = 0 self.tx_idx = 0 self.rx_ll_dl = 0 self.tx_state = ISOTP_IDLE self.tx_timeout_handle = None # type: Optional[TimeoutScheduler.Handle] # noqa: E501 self.rx_timeout_handle = None # type: Optional[TimeoutScheduler.Handle] # noqa: E501 self.rx_thread_started = Event() self.rx_thread = AsyncSniffer( store=False, opened_socket=can_socket, prn=self.on_can_recv, started_callback=self.rx_thread_started.set) self.tx_mutex = Lock() self.rx_mutex = Lock() self.send_mutex = Lock() self.tx_done = Event() self.tx_exception = None # type: Optional[str] self.tx_callbacks = [] # type: List[Callable[[], None]] self.rx_callbacks = [] # type: List[Callable[[bytes], None]] self.rx_thread.start() self.rx_thread_started.wait(5)
class ISOTPSocketImplementation: """ Implementation of an ISOTP "state machine". Most of the ISOTP logic was taken from https://github.com/hartkopp/can-isotp/blob/master/net/can/isotp.c This class is separated from ISOTPSoftSocket to make sure the background thread can't hold a reference to ISOTPSoftSocket, allowing it to be collected by the GC. :param can_socket: a CANSocket instance, preferably filtering only can frames with identifier equal to did :param src_id: the CAN identifier of the sent CAN frames :param dst_id: the CAN identifier of the received CAN frames :param padding: If True, pads sending packets with 0x00 which not count to the payload. Does not affect receiving packets. :param extended_addr: Extended Address byte to be added at the beginning of every CAN frame _sent_ by this object. Can be None in order to disable extended addressing on sent frames. :param extended_rx_addr: Extended Address byte expected to be found at the beginning of every CAN frame _received_ by this object. Can be None in order to disable extended addressing on received frames. :param rx_block_size: Block Size byte to be included in every Control Flow Frame sent by this object. The default value of 0 means that all the data will be received in a single block. :param stmin: Time Minimum Separation byte to be included in every Control Flow Frame sent by this object. The default value of 0 indicates that the peer will not wait any time between sending frames. :param listen_only: Disables send of flow control frames """ def __init__(self, can_socket, # type: "CANSocket" src_id, # type: int dst_id, # type: int padding=False, # type: bool extended_addr=None, # type: Optional[int] extended_rx_addr=None, # type: Optional[int] rx_block_size=0, # type: int stmin=0, # type: int listen_only=False # type: bool ): # type: (...) -> None self.can_socket = can_socket self.dst_id = dst_id self.src_id = src_id self.padding = padding self.fc_timeout = 1 self.cf_timeout = 1 self.filter_warning_emitted = False self.extended_rx_addr = extended_rx_addr self.ea_hdr = b"" if extended_addr is not None: self.ea_hdr = struct.pack("B", extended_addr) self.listen_only = listen_only self.rxfc_bs = rx_block_size self.rxfc_stmin = stmin self.rx_queue = ObjectPipe() self.rx_len = -1 self.rx_buf = None # type: Optional[bytes] self.rx_sn = 0 self.rx_bs = 0 self.rx_idx = 0 self.rx_ts = 0.0 # type: Union[float, EDecimal] self.rx_state = ISOTP_IDLE self.txfc_bs = 0 self.txfc_stmin = 0 self.tx_gap = 0 self.tx_buf = None # type: Optional[bytes] self.tx_sn = 0 self.tx_bs = 0 self.tx_idx = 0 self.rx_ll_dl = 0 self.tx_state = ISOTP_IDLE self.tx_timeout_handle = None # type: Optional[TimeoutScheduler.Handle] # noqa: E501 self.rx_timeout_handle = None # type: Optional[TimeoutScheduler.Handle] # noqa: E501 self.rx_thread_started = Event() self.rx_thread = AsyncSniffer( store=False, opened_socket=can_socket, prn=self.on_can_recv, started_callback=self.rx_thread_started.set) self.tx_mutex = Lock() self.rx_mutex = Lock() self.send_mutex = Lock() self.tx_done = Event() self.tx_exception = None # type: Optional[str] self.tx_callbacks = [] # type: List[Callable[[], None]] self.rx_callbacks = [] # type: List[Callable[[bytes], None]] self.rx_thread.start() self.rx_thread_started.wait(5) def __del__(self): # type: () -> None self.close() def can_send(self, load): # type: (bytes) -> None if self.padding: load += b"\xCC" * (CAN_MAX_DLEN - len(load)) if self.src_id is None or self.src_id <= 0x7ff: self.can_socket.send(CAN(identifier=self.src_id, data=load)) else: self.can_socket.send(CAN(identifier=self.src_id, flags="extended", data=load)) def on_can_recv(self, p): # type: (Packet) -> None if not isinstance(p, CAN): raise Scapy_Exception("argument is not a CAN frame") if p.identifier != self.dst_id: if not self.filter_warning_emitted and conf.verb >= 2: warning("You should put a filter for identifier=%x on your " "CAN socket", self.dst_id) self.filter_warning_emitted = True else: self.on_recv(p) def close(self): # type: () -> None if self.rx_thread.thread and self.rx_thread.thread.is_alive(): self.rx_thread.stop(True) def _rx_timer_handler(self): # type: () -> None """Method called every time the rx_timer times out, due to the peer not sending a consecutive frame within the expected time window""" with self.rx_mutex: if self.rx_state == ISOTP_WAIT_DATA: # we did not get new data frames in time. # reset rx state self.rx_state = ISOTP_IDLE if conf.verb > 2: warning("RX state was reset due to timeout") def _tx_timer_handler(self): # type: () -> None """Method called every time the tx_timer times out, which can happen in two situations: either a Flow Control frame was not received in time, or the Separation Time Min is expired and a new frame must be sent.""" with self.tx_mutex: if (self.tx_state == ISOTP_WAIT_FC or self.tx_state == ISOTP_WAIT_FIRST_FC): # we did not get any flow control frame in time # reset tx state self.tx_state = ISOTP_IDLE self.tx_exception = "TX state was reset due to timeout" self.tx_done.set() raise Scapy_Exception(self.tx_exception) elif self.tx_state == ISOTP_SENDING: # push out the next segmented pdu src_off = len(self.ea_hdr) max_bytes = 7 - src_off if self.tx_buf is None: self.tx_exception = "TX buffer is not filled" raise Scapy_Exception(self.tx_exception) while 1: load = self.ea_hdr load += struct.pack("B", N_PCI_CF + self.tx_sn) load += self.tx_buf[self.tx_idx:self.tx_idx + max_bytes] self.can_send(load) self.tx_sn = (self.tx_sn + 1) % 16 self.tx_bs += 1 self.tx_idx += max_bytes if len(self.tx_buf) <= self.tx_idx: # we are done self.tx_state = ISOTP_IDLE self.tx_done.set() for cb in self.tx_callbacks: cb() return if self.txfc_bs != 0 and self.tx_bs >= self.txfc_bs: # stop and wait for FC self.tx_state = ISOTP_WAIT_FC self.tx_timeout_handle = TimeoutScheduler.schedule( self.fc_timeout, self._tx_timer_handler) return if self.tx_gap == 0: continue else: # stop and wait for tx gap self.tx_timeout_handle = TimeoutScheduler.schedule( self.tx_gap, self._tx_timer_handler) return def on_recv(self, cf): # type: (Packet) -> None """Function that must be called every time a CAN frame is received, to advance the state machine.""" data = bytes(cf.data) if len(data) < 2: return ae = 0 if self.extended_rx_addr is not None: ae = 1 if len(data) < 3: return if six.indexbytes(data, 0) != self.extended_rx_addr: return n_pci = six.indexbytes(data, ae) & 0xf0 if n_pci == N_PCI_FC: with self.tx_mutex: self._recv_fc(data[ae:]) elif n_pci == N_PCI_SF: with self.rx_mutex: self._recv_sf(data[ae:], cf.time) elif n_pci == N_PCI_FF: with self.rx_mutex: self._recv_ff(data[ae:], cf.time) elif n_pci == N_PCI_CF: with self.rx_mutex: self._recv_cf(data[ae:]) def _recv_fc(self, data): # type: (bytes) -> None """Process a received 'Flow Control' frame""" 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 self.tx_exception = "CF frame discarded because it was too short" self.tx_done.set() raise Scapy_Exception(self.tx_exception) # 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 self.tx_exception = "Overflow happened at the receiver side" self.tx_done.set() raise Scapy_Exception(self.tx_exception) else: self.tx_state = ISOTP_IDLE self.tx_exception = "Unknown FC frame type" self.tx_done.set() raise Scapy_Exception(self.tx_exception) def _recv_sf(self, data, ts): # type: (bytes, Union[float, EDecimal]) -> None """Process a received 'Single Frame' frame""" 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)) for cb in self.rx_callbacks: cb(msg) def _recv_ff(self, data, ts): # type: (bytes, Union[float, EDecimal]) -> None """Process a received 'First Frame' frame""" 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 _recv_cf(self, data): # type: (bytes) -> None """Process a received 'Consecutive Frame' frame""" 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: raise Scapy_Exception("rx_buf not filled with data!") 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)) for cb in self.rx_callbacks: cb(self.rx_buf) 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.can_send(load) # wait for another CF self.rx_timeout_handle = TimeoutScheduler.schedule( self.cf_timeout, self._rx_timer_handler) def begin_send(self, x): # type: (bytes) -> None """Begins sending an ISOTP message. This method does not block.""" with self.tx_mutex: if self.tx_state != ISOTP_IDLE: raise Scapy_Exception("Socket is already sending, retry later") self.tx_done.clear() self.tx_exception = None self.tx_state = ISOTP_SENDING length = len(x) if length > ISOTP_MAX_DLEN_2015: raise Scapy_Exception("Too much data for ISOTP message") if len(self.ea_hdr) + length <= 7: # send a single frame data = self.ea_hdr data += struct.pack("B", length) data += x self.tx_state = ISOTP_IDLE self.can_send(data) self.tx_done.set() for cb in self.tx_callbacks: cb() return # send the first frame data = self.ea_hdr if length > ISOTP_MAX_DLEN: data += struct.pack(">HI", 0x1000, length) else: data += struct.pack(">H", 0x1000 | length) load = x[0:8 - len(data)] data += load self.can_send(data) self.tx_buf = x self.tx_sn = 1 self.tx_bs = 0 self.tx_idx = len(load) self.tx_state = ISOTP_WAIT_FIRST_FC self.tx_timeout_handle = TimeoutScheduler.schedule( self.fc_timeout, self._tx_timer_handler) def send(self, p): # type: (bytes) -> None """Send an ISOTP frame and block until the message is sent or an error happens.""" with self.send_mutex: self.begin_send(p) # Wait until the tx callback is called send_done = self.tx_done.wait(30) if self.tx_exception is not None: raise Scapy_Exception(self.tx_exception) if not send_done: raise Scapy_Exception("ISOTP send not completed in 30s") return def recv(self, timeout=None): # type: (Optional[int]) -> Optional[Tuple[bytes, Union[float, EDecimal]]] # noqa: E501 """Receive an ISOTP frame, blocking if none is available in the buffer for at most 'timeout' seconds.""" try: return self.rx_queue.recv() except IndexError: return None
def __init__(self, *args, **kwargs): self.client_pipe = ObjectPipe() super(NTLM_Client, self).__init__(*args, **kwargs)
def _run(self, count=0, store=True, offline=None, quiet=False, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, iface=None, started_callback=None, session=None, session_args=[], session_kwargs={}, *arg, **karg): self.running = True # Start main thread # instantiate session if not isinstance(session, DefaultSession): session = session or DefaultSession session = session(prn=prn, store=store, *session_args, **session_kwargs) else: session.prn = prn session.store = store # sniff_sockets follows: {socket: label} sniff_sockets = {} if opened_socket is not None: if isinstance(opened_socket, list): sniff_sockets.update( (s, "socket%d" % i) for i, s in enumerate(opened_socket)) elif isinstance(opened_socket, dict): sniff_sockets.update( (s, label) for s, label in six.iteritems(opened_socket)) else: sniff_sockets[opened_socket] = "socket0" if offline is not None: flt = karg.get('filter') if isinstance(offline, list) and \ all(isinstance(elt, str) for elt in offline): sniff_sockets.update( (PcapReader(fname if flt is None else tcpdump( fname, args=["-w", "-"], flt=flt, getfd=True)), fname) for fname in offline) elif isinstance(offline, dict): sniff_sockets.update( (PcapReader(fname if flt is None else tcpdump( fname, args=["-w", "-"], flt=flt, getfd=True)), label) for fname, label in six.iteritems(offline)) else: # Write Scapy Packet objects to a pcap file def _write_to_pcap(packets_list): filename = get_temp_file(autoext=".pcap") wrpcap(filename, offline) return filename, filename if isinstance(offline, Packet): tempfile_written, offline = _write_to_pcap([offline]) elif isinstance(offline, list) and \ all(isinstance(elt, Packet) for elt in offline): tempfile_written, offline = _write_to_pcap(offline) sniff_sockets[PcapReader(offline if flt is None else tcpdump( offline, args=["-w", "-"], flt=flt, getfd=True, quiet=quiet))] = offline if not sniff_sockets or iface is not None: iface = resolve_iface(iface or conf.iface) if L2socket is None: L2socket = iface.l2listen() if isinstance(iface, list): sniff_sockets.update( (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), ifname) for ifname in iface) elif isinstance(iface, dict): sniff_sockets.update( (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), iflabel) for ifname, iflabel in six.iteritems(iface)) else: sniff_sockets[L2socket(type=ETH_P_ALL, iface=iface, *arg, **karg)] = iface # Get select information from the sockets _main_socket = next(iter(sniff_sockets)) select_func = _main_socket.select _backup_read_func = _main_socket.__class__.recv nonblocking_socket = _main_socket.nonblocking_socket # We check that all sockets use the same select(), or raise a warning if not all(select_func == sock.select for sock in sniff_sockets): warning("Warning: inconsistent socket types ! " "The used select function " "will be the one of the first socket") if nonblocking_socket: # select is non blocking def stop_cb(): self.continue_sniff = False self.stop_cb = stop_cb close_pipe = None else: # select is blocking: Add special control socket from scapy.automaton import ObjectPipe close_pipe = ObjectPipe() sniff_sockets[close_pipe] = "control_socket" def stop_cb(): if self.running: close_pipe.send(None) self.continue_sniff = False self.stop_cb = stop_cb try: if started_callback: started_callback() self.continue_sniff = True # Start timeout if timeout is not None: stoptime = time.time() + timeout remain = None while sniff_sockets and self.continue_sniff: if timeout is not None: remain = stoptime - time.time() if remain <= 0: break sockets, read_func = select_func(sniff_sockets, remain) read_func = read_func or _backup_read_func dead_sockets = [] for s in sockets: if s is close_pipe: break try: p = read_func(s) except EOFError: # End of stream try: s.close() except Exception: pass dead_sockets.append(s) continue except Exception as ex: msg = " It was closed." try: # Make sure it's closed s.close() except Exception as ex: msg = " close() failed with '%s'" % ex warning("Socket %s failed with '%s'." % (s, ex) + msg) dead_sockets.append(s) if conf.debug_dissector >= 2: raise continue if p is None: continue if lfilter and not lfilter(p): continue p.sniffed_on = sniff_sockets[s] # on_packet_received handles the prn/storage session.on_packet_received(p) # check if (stop_filter and stop_filter(p)) or \ (0 < count <= session.count): self.continue_sniff = False break # Removed dead sockets for s in dead_sockets: del sniff_sockets[s] except KeyboardInterrupt: pass self.running = False if opened_socket is None: for s in sniff_sockets: s.close() elif close_pipe: close_pipe.close() self.results = session.toPacketList()
def _gen_high_data(self, msg): ObjectPipe.send(self, (msg, True, False))
def _run(self, count=0, # type: int store=True, # type: bool offline=None, # type: Any quiet=False, # type: bool prn=None, # type: Optional[Callable[[Packet], Any]] lfilter=None, # type: Optional[Callable[[Packet], bool]] L2socket=None, # type: Optional[Type[SuperSocket]] timeout=None, # type: Optional[int] opened_socket=None, # type: Optional[SuperSocket] stop_filter=None, # type: Optional[Callable[[Packet], bool]] iface=None, # type: Optional[_GlobInterfaceType] started_callback=None, # type: Optional[Callable[[], Any]] session=None, # type: Optional[_GlobSessionType] session_kwargs={}, # type: Dict[str, Any] **karg # type: Any ): # type: (...) -> None self.running = True # Start main thread # instantiate session if not isinstance(session, DefaultSession): session = session or DefaultSession session = session(prn=prn, store=store, **session_kwargs) else: session.prn = prn session.store = store # sniff_sockets follows: {socket: label} sniff_sockets = {} # type: Dict[SuperSocket, _GlobInterfaceType] if opened_socket is not None: if isinstance(opened_socket, list): sniff_sockets.update( (s, "socket%d" % i) for i, s in enumerate(opened_socket) ) elif isinstance(opened_socket, dict): sniff_sockets.update( (s, label) for s, label in six.iteritems(opened_socket) ) else: sniff_sockets[opened_socket] = "socket0" if offline is not None: flt = karg.get('filter') if isinstance(offline, str): # Single file offline = [offline] if isinstance(offline, list) and \ all(isinstance(elt, str) for elt in offline): # List of files sniff_sockets.update((PcapReader( fname if flt is None else tcpdump(fname, args=["-w", "-"], flt=flt, getfd=True, quiet=quiet) ), fname) for fname in offline) elif isinstance(offline, dict): # Dict of files sniff_sockets.update((PcapReader( fname if flt is None else tcpdump(fname, args=["-w", "-"], flt=flt, getfd=True, quiet=quiet) ), label) for fname, label in six.iteritems(offline)) elif isinstance(offline, (Packet, PacketList, list)): # Iterables (list of packets, PacketList..) offline = IterSocket(offline) sniff_sockets[offline if flt is None else PcapReader( tcpdump(offline, args=["-w", "-"], flt=flt, getfd=True, quiet=quiet) )] = offline else: # Other (file descriptors...) sniff_sockets[PcapReader( offline if flt is None else tcpdump(offline, args=["-w", "-"], flt=flt, getfd=True, quiet=quiet) )] = offline if not sniff_sockets or iface is not None: # The _RL2 function resolves the L2socket of an iface _RL2 = lambda i: L2socket or resolve_iface(i).l2listen() # type: Callable[[_GlobInterfaceType], Callable[..., SuperSocket]] # noqa: E501 if isinstance(iface, list): sniff_sockets.update( (_RL2(ifname)(type=ETH_P_ALL, iface=ifname, **karg), ifname) for ifname in iface ) elif isinstance(iface, dict): sniff_sockets.update( (_RL2(ifname)(type=ETH_P_ALL, iface=ifname, **karg), iflabel) for ifname, iflabel in six.iteritems(iface) ) else: iface = iface or conf.iface sniff_sockets[_RL2(iface)(type=ETH_P_ALL, iface=iface, **karg)] = iface # Get select information from the sockets _main_socket = next(iter(sniff_sockets)) select_func = _main_socket.select nonblocking_socket = _main_socket.nonblocking_socket # We check that all sockets use the same select(), or raise a warning if not all(select_func == sock.select for sock in sniff_sockets): warning("Warning: inconsistent socket types ! " "The used select function " "will be the one of the first socket") if not nonblocking_socket: # select is blocking: Add special control socket from scapy.automaton import ObjectPipe close_pipe = ObjectPipe() sniff_sockets[close_pipe] = "control_socket" def stop_cb(): # type: () -> None if self.running: close_pipe.send(None) self.continue_sniff = False self.stop_cb = stop_cb else: # select is non blocking def stop_cb(): # type: () -> None self.continue_sniff = False self.stop_cb = stop_cb close_pipe = None try: if started_callback: started_callback() self.continue_sniff = True # Start timeout if timeout is not None: stoptime = time.time() + timeout remain = None while sniff_sockets and self.continue_sniff: if timeout is not None: remain = stoptime - time.time() if remain <= 0: break sockets = select_func(list(sniff_sockets.keys()), remain) dead_sockets = [] for s in sockets: if s is close_pipe: break try: p = s.recv() except EOFError: # End of stream try: s.close() except Exception: pass dead_sockets.append(s) continue except Exception as ex: msg = " It was closed." try: # Make sure it's closed s.close() except Exception as ex2: msg = " close() failed with '%s'" % ex2 warning( "Socket %s failed with '%s'." % (s, ex) + msg ) dead_sockets.append(s) if conf.debug_dissector >= 2: raise continue if p is None: continue if lfilter and not lfilter(p): continue p.sniffed_on = sniff_sockets[s] # on_packet_received handles the prn/storage session.on_packet_received(p) # check if (stop_filter and stop_filter(p)) or \ (0 < count <= session.count): self.continue_sniff = False break # Removed dead sockets for s in dead_sockets: del sniff_sockets[s] except KeyboardInterrupt: pass self.running = False if opened_socket is None: for s in sniff_sockets: s.close() elif close_pipe: close_pipe.close() self.results = session.toPacketList()
class _NTLM_Automaton(Automaton): def __init__(self, sock, **kwargs): # type: (StreamSocket, Any) -> None self.token_pipe = ObjectPipe() self.values = {} for key, dflt in [("DROP_MIC_v1", False), ("DROP_MIC_v2", False)]: setattr(self, key, kwargs.pop(key, dflt)) self.DROP_MIC = self.DROP_MIC_v1 or self.DROP_MIC_v2 super(_NTLM_Automaton, self).__init__(recvsock=lambda **kwargs: sock, ll=lambda **kwargs: sock, **kwargs) def _get_token(self, token): from scapy.layers.gssapi import (GSSAPI_BLOB, SPNEGO_negToken, SPNEGO_Token) negResult = None MIC = None if not token: return None, negResult, MIC if isinstance(token, bytes): ntlm = NTLM_Header(token) elif isinstance(token, conf.raw_layer): ntlm = NTLM_Header(token.load) else: if isinstance(token, GSSAPI_BLOB): token = token.innerContextToken if isinstance(token, SPNEGO_negToken): token = token.token if hasattr(token, "mechListMIC") and token.mechListMIC: MIC = token.mechListMIC.value if hasattr(token, "negResult"): negResult = token.negResult try: ntlm = token.mechToken except AttributeError: ntlm = token.responseToken if isinstance(ntlm, SPNEGO_Token): ntlm = ntlm.value if isinstance(ntlm, ASN1_STRING): ntlm = NTLM_Header(ntlm.val) if isinstance(ntlm, conf.raw_layer): ntlm = NTLM_Header(ntlm.load) if self.DROP_MIC_v1 or self.DROP_MIC_v2: if isinstance(ntlm, NTLM_AUTHENTICATE): ntlm.MIC = b"\0" * 16 ntlm.NtChallengeResponseLen = None ntlm.NtChallengeResponseMaxLen = None ntlm.EncryptedRandomSessionKeyBufferOffset = None if self.DROP_MIC_v2: ChallengeResponse = next(v[1] for v in ntlm.Payload if v[0] == 'NtChallengeResponse') i = next(i for i, k in enumerate(ChallengeResponse.AvPairs) if k.AvId == 0x0006) ChallengeResponse.AvPairs.insert( i + 1, AV_PAIR(AvId="MsvAvFlags", Value=0)) return ntlm, negResult, MIC def received_ntlm_token(self, ntlm): self.token_pipe.send(ntlm) def get(self, attr, default=None): if default is not None: return self.values.get(attr, default) return self.values[attr] def end(self): self.listen_sock.close() self.stop()