Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
 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
Ejemplo n.º 4
0
 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]
Ejemplo n.º 5
0
    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()
Ejemplo n.º 6
0
 def _exhaust(self):
     # type: () -> None
     ObjectPipe.send(self, (None, None, True))
Ejemplo n.º 7
0
 def _gen_high_data(self, msg):
     # type: (str) -> None
     ObjectPipe.send(self, (msg, True, False))
Ejemplo n.º 8
0
 def __init__(self, name=None):
     # type: (Optional[str]) -> None
     Pipe.__init__(self, name=name)
     ObjectPipe.__init__(self, name)
     self.is_exhausted = False
Ejemplo n.º 9
0
 def _exhaust(self):
     ObjectPipe.send(self, (None, None, True))
Ejemplo n.º 10
0
 def _gen_data(self, msg):
     ObjectPipe.send(self, (msg, False, False))
Ejemplo n.º 11
0
 def __init__(self, name=None):
     Pipe.__init__(self, name=name)
     ObjectPipe.__init__(self)
     self.is_exhausted = False
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
 def __init__(self, *args, **kwargs):
     self.client_pipe = ObjectPipe()
     super(NTLM_Client, self).__init__(*args, **kwargs)
Ejemplo n.º 15
0
    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()
Ejemplo n.º 16
0
 def _gen_high_data(self, msg):
     ObjectPipe.send(self, (msg, True, False))
Ejemplo n.º 17
0
    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()
Ejemplo n.º 18
0
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()