Beispiel #1
0
class ConnectionSniffer(Supervisor):
    """
    Multiple channels connection sniffing supervisor.

    This supervisor drive the sniffing interface to sniff for new BLE
    connections, and allows to jam and hijack them on the fly.
    """

    STATE_IDLE = 0
    STATE_SYNCING = 1
    STATE_FOLLOWING = 2
    STATE_HIJACKING = 3
    STATE_HIJACKED = 4

    def __init__(self, bd_address='ff:ff:ff:ff:ff:ff', devices=None):
        super().__init__()
        self.interface = MultiSnifferInterface(3, devices=devices)
        self.bd_address = bd_address

        self.sniff()

        # Retrieve the user session
        try:
            self.session = BtlejackSession.get_instance()
        except BtlejackSessionError as session_error:
            # something went wrong, wont keep the session
            self.session = None


    def sniff(self):
        """
        Start sniffing for new connections.
        """
        self.interface.sniff_connection(
            self.bd_address
        )
        self.state = self.STATE_SYNCING
        self.access_address = None
        self.sent_packet = False

    def jam(self):
        """
        Enable jamming.
        """
        if self.state == self.STATE_FOLLOWING:
            self.interface.enable_jamming(True)

    def hijack(self):
        """
        Enable hijacking
        """
        if self.state == self.STATE_FOLLOWING:
            self.state = self.STATE_HIJACKING
            self.interface.enable_hijacking(True)

    def process_packets(self):
        packets = self.interface.read_packet()
        if len(packets) > 0:
            for pkt in packets:
                pkt = PacketRegistry.decode(pkt)
                self.on_packet_received(pkt)

    def on_packet_received(self, packet):
        """
        Packet handler.
        """
        if isinstance(packet, VerbosePacket) or isinstance(packet, DebugPacket):
            super().on_packet_received(packet)
        elif isinstance(packet, ConnectionLostNotification):
            self.on_connection_lost()
        else:
            if self.state == self.STATE_SYNCING:
                if isinstance(packet, ConnectionRequestNotification):
                    # Rebuild connection packet
                    class rawpacket:
                        def __init__(self, payload):
                            self.data = payload
                    pkt = bytes([0]*10) +bytes([0x05, 0x22]) + packet.inita + packet.adva+packet.payload
                    self.access_address = 0x8e89bed6
                    self.on_ll_packet(rawpacket(pkt))

                    # Save connection parameters
                    if self.session is not None:
                        self.session.add_connection(
                            packet.access_address,
                            {
                                'crcinit': packet.crc_init
                            }
                        )
                        self.session.save()


                    self.access_address = packet.access_address
                    self.on_connection(
                        packet.inita,
                        packet.adva,
                        packet.crc_init,
                        packet.hop_interval,
                        packet.hop_increment,
                        packet.channel_map,
                        packet.timeout
                    )
                    self.state = self.STATE_FOLLOWING
            elif self.state == self.STATE_FOLLOWING:
                self.on_ll_packet(packet)
            elif self.state == self.STATE_HIJACKING:
                if isinstance(packet, HijackStatusNotification):
                    if packet.status:
                        self.state = self.STATE_HIJACKED
                        self.on_hijacking_success()
                    else:
                        self.state = self.STATE_IDLE
                        self.on_hijacking_failed()
            elif self.state == self.STATE_HIJACKED:
                if isinstance(packet, SendPacketResponse):
                    self.sent_packet = False
                else:
                    self.on_ll_packet(packet)

    def on_connection(self, inita, adva, crc_init, interval, increment, channel_map):
        print('Got connection !')

    def on_ll_packet(self, packet):
        """
        A BLE LL packet has been captured.
        """
        print(packet)

    def on_hijacking_success(self):
        """
        Hijacking was successful, hijacker now owns this connection.
        """
        pass

    def on_hijacking_failed(self):
        """
        Could not hijack this connection.
        """
        pass

    def on_connection_lost(self):
        """
        Connection has been lost.
        """
        pass

    def send_packet(self, packet):
        """
        Send a BLE LL packet.
        """
        self.packet_sent = self.interface.send_packet(packet)
Beispiel #2
0
class ConnectionRecovery(Supervisor):
    """
    Existing connection recovery supervisor.

    This supervisor drives the sniffing interface to recover an existing
    connection parameters, and then allows to jam and hijack on the fly.
    """

    STATE_IDLE = 0
    STATE_RECOVER_CRC = 1
    STATE_RECOVER_CHM = 2
    STATE_RECOVER_HOPINTER = 3
    STATE_RECOVER_HOPINC = 4
    STATE_FOLLOWING = 5
    STATE_HIJACKING = 6
    STATE_HIJACKED = 7
    STATE_RECOVER_CCHM = 8

    def __init__(self, access_address, channel_map=None, hop_interval=None, crc=None, devices=None, baudrate=115200, timeout=0):
        super().__init__()

        # Retrieve the user session
        try:
            self.session = BtlejackSession.get_instance()
        except BtlejackSessionError as session_error:
            # something went wrong, wont keep the session
            self.session = None

        if devices is not None:
            self.interface = MultiSnifferInterface(len(devices), baudrate, devices)
        else:
            self.interface = MultiSnifferInterface(999)
        self.state = self.STATE_RECOVER_CRC
        self.chm_provided = (channel_map is not None)
        self.crc_provide = (crc is not None)
        self.hop_provided = (hop_interval is not None)
        self.access_address = access_address
        self.hop_interval = hop_interval
        self.chm = channel_map
        self.packet_sent = False
        self.crc = crc
        self.cchm_notifications = 0
        self.cchm = 0
        self.timeout = timeout

        # Launch recovery based on the provided informations.
        if self.crc is not None:

            # Save CRC in session if possible
            if self.session is not None:
                self.session.add_connection(
                    self.access_address,
                    {'crcinit': self.crc}
                )
                self.session.save()

            if self.chm is not None:
                self.state = self.STATE_RECOVER_HOPINTER
                self.interface.recover_hop(access_address, self.crc, self.chm)
            else:
                self.state = self.STATE_RECOVER_CCHM
                self.interface.recover_chm(access_address, self.crc, self.timeout)
        else:
            self.state = self.STATE_RECOVER_CRC
            self.interface.recover_crcinit(access_address)


    def jam(self):
        """
        Enable jamming.
        """
        if self.state == self.STATE_FOLLOWING:
            self.interface.enable_jamming(True)

    def hijack(self):
        """
        Enable hijacking
        """
        if self.state == self.STATE_FOLLOWING:
            self.state = self.STATE_HIJACKING
            self.interface.enable_hijacking(True)

    def on_packet_received(self, packet):
        """
        Packet handler.
        """
        #print(packet)
        if isinstance(packet, VerbosePacket) or isinstance(packet, DebugPacket):
            super().on_packet_received(packet)
        elif isinstance(packet, ConnectionLostNotification):
            self.on_connection_lost()
        else:
            if self.state == self.STATE_RECOVER_CRC:
                if isinstance(packet, CrcNotification):
                    # Forward CRC
                    self.on_crc(packet.crc)
                    self.crc = packet.crc

                    # Save CRC in session if possible
                    if self.session is not None:
                        self.session.add_connection(
                            self.access_address,
                            {'crcinit': self.crc}
                        )
                        self.session.save()

                    # If channel map is provided
                    if self.chm_provided:
                        #self.on_chm(self.chm)
                        self.state = self.STATE_RECOVER_HOPINTER
                    else:
                        # We are going to recover the channel map
                        # but in a collaborative way if we have
                        # many interfaces available.
                        if self.interface.get_nb_interfaces() >= 1:
                            # If more than one interface, it is more
                            # efficient to do a collaborative chm recovery
                            self.state = self.STATE_RECOVER_CCHM

                            # we reset all the interfaces
                            self.interface.reset()
                            self.cchm_notifications = 0
                            self.cchm = 0

                            # and ask for a collaborative channel mapping
                            self.interface.recover_chm(
                                self.access_address,
                                self.crc,
                                self.timeout
                            )
                        else:
                            # otherwise, we continue with the 'normal' way
                            self.state = self.STATE_RECOVER_CHM

            elif self.state == self.STATE_RECOVER_CHM:
                if isinstance(packet, ChannelMapNotification):
                    self.on_chm(packet.channel_map)

                    if self.hop_provided:
                        self.state = self.STATE_RECOVER_HOPINC
                    else:
                        self.state = self.STATE_RECOVER_HOPINTER
            elif self.state == self.STATE_RECOVER_CCHM:
                if isinstance(packet, ChannelMapNotification):
                    # we expect to get as many chm notification as interfaces
                    self.cchm |= packet.channel_map
                    self.cchm_notifications += 1
                    if self.cchm_notifications == self.interface.get_nb_interfaces():
                        self.state = self.STATE_RECOVER_HOPINTER
                        self.on_chm(self.cchm)
            elif self.state == self.STATE_RECOVER_HOPINTER:
                if isinstance(packet, HopIntervalNotification):
                    # Save CHM too in session if possible
                    self.on_hopinterval(packet.interval)
                    self.state = self.STATE_RECOVER_HOPINC
            elif self.state == self.STATE_RECOVER_HOPINC:
                if isinstance(packet, HopIncrementNotification):
                    self.state = self.STATE_FOLLOWING
                    self.on_hopincrement(packet.increment)
            elif self.state == self.STATE_FOLLOWING:
                self.on_ll_packet(packet)
            elif self.state == self.STATE_HIJACKING:
                if isinstance(packet, HijackStatusNotification):
                    if packet.status:
                        self.state = self.STATE_HIJACKED
                        self.on_hijacking_success()
                    else:
                        self.state = self.STATE_IDLE
                        self.on_hijacking_failed()
            elif self.state == self.STATE_HIJACKED:
                if isinstance(packet, SendPacketResponse):
                    self.sent_packet = False
                else:
                    self.on_ll_packet(packet)

    def on_crc(self, crc):
        """
        Connection CRC has been recovered.
        """
        print('CRC: %06x' % crc)

    def on_chm(self, chm):
        """
        Channel map has been recovered.
        """
        print('sup:on_chm')
        print('CHM: %010x' % chm)
        self.state = self.STATE_RECOVER_HOPINTER
        self.chm = chm
        self.recover_hop(
            self.access_address,
            self.crc,
            self.chm
        )

    def on_hopinterval(self, interval):
        """
        Hop interval has been recovered.
        """
        print('Interval: %d' % interval)

    def on_hopincrement(self, increment):
        """
        Hop increment has been recovered.
        """
        print('Increment: %d' % increment)

    def on_ll_packet(self, packet):
        """
        A BLE LL packet has been captured.
        """
        print(packet)

    def on_hijacking_success(self):
        """
        Hijacking was successful, hijacker now owns this connection.
        """
        pass

    def on_hijacking_failed(self):
        """
        Could not hijack this connection.
        """
        pass

    def on_connection_lost(self):
        """
        Connection has been lost.
        """
        pass

    def send_packet(self, packet):
        """
        Send a BLE LL packet.
        """
        self.packet_sent = self.interface.send_packet(packet)