首页
社区
课程
招聘
[原创] CVE-2019-2025(水滴) 漏洞利用
发表于: 2019-9-30 10:31 26026

[原创] CVE-2019-2025(水滴) 漏洞利用

2019-9-30 10:31
26026

本文仅供学习交流,如作他用所承受的法律责任一概与作者无关


一、漏洞介绍

CVE-2019-2025(水滴漏洞)由c0re team提出,并在HITBSecConf2019分享了漏洞利用方法,遗憾的是由于没有exploit源码,对于学习此漏洞还是不够直接。本文将从exploit源码的角度来讲解此漏洞,在pixel手机上可实现99%概率成功root。同时也分享自己在写此漏洞的调试方式和解决各种问题的思路。


二、漏洞原理

关于原理我这里不再过多重述,请看“水滴”来袭:详解Binder内核通杀漏洞。简单说的两个线程会产生竞争关系。一个是client线程,一个是server线程。



图片1引用于《D2T2 - Binder - The Bridge to Root - Hongli Han & Mingjian Zhou》

client线程执行BC_FREE_BUFFER,代码如下:



图片2引用于《D2T2 - Binder - The Bridge to Root - Hongli Han & Mingjian Zhou》

server线程执行BC_REPLY,代码如下:


图片3引用于《D2T2 - Binder - The Bridge to Root - Hongli Han & Mingjian Zhou》


为什么要释放两次binder_buffer呢?


图片4引用于《D2T2 - Binder - The Bridge to Root - Hongli Han & Mingjian Zhou》

在前一个binder_buffer释放时,由于需要合并后一个binder_buffer,才会真正kfree后一个binder_buffer。


三、漏洞细节

1、Client线程如何才能执行BC_FREE_BUFFER,Server进程如何才能执行BC_REPLY(binder_alloc_new_buffer)。

此部分理解起来不难,由于使用了很多framework层的api,所以需要在android源码环境下编译。


2、我们刚刚说的执行BC_FREE_BUFFER,是需要提前分配binder_buffer,也就是分配后才能释放;这步叫放置诱饵。


3、竞争

起了两个线程,线程1执行BC_FREE_BUFFER,线程2会通过binder请求mediaserver进程执行BC_REPLY(binder_alloc_new_buffer)。线程1通过条件变量来唤醒线程2。

线程1和线程2同步执行这两个操作,形成竞争。为什么usleep(450),这个因为线程2通过binder进程间通信,让mediaserver执行BC_REPLY需要一段时间,根据自己的机器情况调整这个值。总之目的是让Client进程(BC_FREE_BUFFER)和Server进程(BC_REPLY)形成竞争。可以看下图1中所示BC_FREE_BUFFER和BC_REPLY的位置,有助于理解这块。这里所说的Server进程就是mediaserver进程。


4、堆喷

释放binder_buffer后堆喷,使用fsetxattr占用binder_buffer的data_size和data。

因为要实现任意地址写,binder_buffer的data偏移为88,要修改为要写的任意地址,见heap_spray函数。


5、什么地址修改为什么内容呢?

参考内核镜像攻击,[原创] CVE-2017-7533 漏洞利用,0xffffffc001e50840需要被写入0x80000e71。看上面copy_from_user,t->buffer->data被占位为0xffffffc001e50834,源数据和size是tr->data.ptr.buffer和tr->data_size,那么怎么填充源数据和size呢?

具体是如何设置上的呢?读者可以对着binder进程间通信的流程来尝试理解。

此时目的地址设置为0xffffffc001e50834,源数据为0x80000e71,由于rate.mSpeed,rate.mPitch,rate.mStretchMode会占用12个字节,所以执行完copy_from_user后,0xffffffc001e50840地址被填充0x80000e71。此时可以在用户态任意地址读写了。


6、提权

直接patch ns_capable函数,让他返回1,之后就可以成功调用setreuid和setregid了,提权成功。关于ns_capable_addr地址的计算请参考[原创] CVE-2017-7533 漏洞利用。


四、漏洞优化和漏洞调试

1、为了使client和server进程更容易产生竞争。需要使两者运行在同一个cpu上。由于无法sched_setaffinity mediaserver进程的cpuid,我们使用的方法是每个cpu(4核让其中3核忙碌起来)起8个线程,并死循环耗尽cpu。


2、fsetxattr堆喷后会立刻释放内存。

如果仅仅循环调用fsetxattr,你会发现自己的堆喷地址总是一样的,因为分配出来就被立刻free了。所以采用一个申请后并不会马上释放的结构体来占住刚刚被free的内存。我们使用的结构体是inotify_event_info。


图片5引用于《D2T2 - Binder - The Bridge to Root - Hongli Han & Mingjian Zhou》

fsetxattr由于改变了文件的扩展属性,会触发文件监控,调用到inotify_handle_event,调用kmalloc分配event。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-1-31 20:36 被kanxue编辑 ,原因:
收藏
免费 8
支持
分享
最新回复 (45)
雪    币: 324
活跃值: (374)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
2
最后于 2019-9-30 10:55 被Lucaks编辑 ,原因:
2019-9-30 10:40
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
3
Lucaks 牛,大佬可以share exp不,搞了好久没搞出来
已经分享。
2019-9-30 10:45
0
雪    币: 1048
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
 很秀了
2019-9-30 10:54
0
雪    币: 593
活跃值: (817)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
恭喜成功。不敢当大牛,都是基于360的PPT,然后花了更多的时间去调试而已。
但是这个漏洞的精华还是在内核信息泄露,实现后才能实现多机型通杀。
但360PPT似乎并没有给出真正的信息泄露方法,希望还在研究这个漏洞的同学有什么进展也能分享下,谢谢。
2019-9-30 11:24
0
雪    币: 6112
活跃值: (1212)
能力值: (RANK:30 )
在线值:
发帖
回帖
粉丝
6
厉害,赞
2019-9-30 12:39
0
雪    币: 1585
活跃值: (1644)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
大牛
2019-9-30 14:03
0
雪    币: 265
活跃值: (531)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
2019-9-30 17:54
0
雪    币: 24478
活跃值: (62819)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
9
膜,太厉害了!
2019-10-1 07:35
0
雪    币: 196
活跃值: (5826)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
10
2019-10-2 10:58
0
雪    币: 438
活跃值: (228)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
11
是个狼人。
2019-10-6 22:35
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
我准备编译一下,需要注意一些什么吗??
2019-11-8 00:03
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
13
myeanngg 我准备编译一下,需要注意一些什么吗??
在android源码环境下编译。
2019-11-8 08:29
0
雪    币: 139
活跃值: (1145)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
jltxgcy 在android源码环境下编译。
具体在哪个版本下编译有限制吗?
2019-11-8 12:28
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
15
hackbs 具体在哪个版本下编译有限制吗?
我是在android9.0系统上编译的,其他版本你可以试试。
2019-11-11 11:12
0
雪    币: 232
活跃值: (924)
能力值: ( LV4,RANK:44 )
在线值:
发帖
回帖
粉丝
16
大佬,为啥我日志打印出的buff地址都是0
2019-11-18 18:35
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
17
湘北三井同学 大佬,为啥我日志打印出的buff地址都是0
msm# git diff lib/vsprintf.c 
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 0a51559..279d5ff 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1514,7 +1514,7 @@ char *pointer(const char *fmt, char *buf, char *end, void 
                case 3: /* restrict all non-extensioned %p and %pK */
                case 4: /* restrict all non-extensioned %p, %pK, %pa*, %p[rR] */
                default:
-                       ptr = NULL;
+                       //ptr = NULL;
                        break;
                }
                break;
2019-11-18 20:08
0
雪    币: 232
活跃值: (924)
能力值: ( LV4,RANK:44 )
在线值:
发帖
回帖
粉丝
18
jltxgcy msm# git diff lib/vsprintf.c diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 0a51559..279d5ff ...
谢谢大佬,日志出来了,就是竞争不上
2019-11-19 10:33
0
雪    币: 232
活跃值: (924)
能力值: ( LV4,RANK:44 )
在线值:
发帖
回帖
粉丝
19
ffffffc0000b62e8 T ns_capable
ffffffc001ce8000 A swapper_pg_dir
竞争上了,但还是提不了权,buffer data已经被赋值为目标地址了,是我地址没找对吗
<6>[  198.758366] c1    805 !!!!!!!!!!!buffer:ffffffc0cc8ed300,free:0,allow_user_free:1,debugid:58135, data_size:4,offsets_size:0!!!!!!!!!!
<6>[  198.758414] c1   3095 jltxgcy binder free begin, pid:3095, user addr:00000072f3604e38
<6>[  198.758433] c1    805 jltxgcy binder alloc end, target pid:3095, buffer:ffffffc0cc8ed300, buffer user data:72f3604e38
<6>[  198.758448] c1   3095 jltxgcy binder free end, pid:3095, buffer:ffffffc0cc8ed300
<6>[  198.758489] c1   3095 jltxgcy pid:3095, kfree:ffffffc0cc860480, cpuid:1
<6>[  198.758504] c1   3095 jltxgcy binder free begin, pid:3095, user addr:00000072f3604e30
<6>[  198.758511] c1   3095 jltxgcy binder free end, pid:3095, buffer:ffffffc0cfa03c00
<6>[  198.758523] c1   3095 jltxgcy pid:3095, kfree:ffffffc0cc8ed300, cpuid:1
<6>[  198.759832] c1    805 ------------------------------------
<6>[  198.759847] c1    805 jltxgcy binder ocuppy end, target pid:3095, buffer:ffffffc0cc8ed300, free:0, user_allow_free:0, buffer data:ffffffc001ce8834, buffer user data:b2ee86c834, cupid:1
<6>[  198.759858] c1    805 jltxgcy copy_from_user buffer data:ffffffc001ce8834,async_transaction:0
2019-11-19 15:52
0
雪    币: 16369
活跃值: (13118)
能力值: ( LV15,RANK:595 )
在线值:
发帖
回帖
粉丝
20
牛maomao 恭喜成功。不敢当大牛,都是基于360的PPT,然后花了更多的时间去调试而已。 但是这个漏洞的精华还是在内核信息泄露,实现后才能实现多机型通杀。 但360PPT似乎并没有给出真正的信息泄露方法,希望 ...
最近也在调试这个洞,很好奇怎么能有99%成功率。我试了N次就一次成功进入竞争窗口,其他大部分是
BC_FREE_BUFFER xxx no match
我也尝试这不断修改delay,尽量让BC_REPLY到达的时候唤起BC_FREE_BUFFER,
但和当前系统运行状态也有很大关系,这微妙的usleep(450)是不是有点不科学?我是在安卓模拟器上调试的,只有1个core所以两个线程应该是同一个核中的吧?
2019-11-19 21:02
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
21
evilpan 最近也在调试这个洞,很好奇怎么能有99%成功率。我试了N次就一次成功进入竞争窗口,其他大部分是 BC_FREE_BUFFER xxx no match 我也尝试这不断修改delay,尽量让BC_R ...
加下日志定位下情况吧,竞争的漏洞最好用真机,我原来也调试过一个其他竞争的洞,用模拟怎么都不行,真机却很稳定能够竞争成功。
2019-11-20 08:42
0
雪    币: 232
活跃值: (924)
能力值: ( LV4,RANK:44 )
在线值:
发帖
回帖
粉丝
22
老哥,你提权成功过吗,我堆喷成功后,copy_from_user的大小总是4字节,内容也不是init_reply_data里设置的
2019-11-20 17:00
0
雪    币: 232
活跃值: (924)
能力值: ( LV4,RANK:44 )
在线值:
发帖
回帖
粉丝
23
为啥回复20楼回复不了
2019-11-20 17:03
0
雪    币: 16369
活跃值: (13118)
能力值: ( LV15,RANK:595 )
在线值:
发帖
回帖
粉丝
24
jltxgcy 加下日志定位下情况吧,竞争的漏洞最好用真机,我原来也调试过一个其他竞争的洞,用模拟怎么都不行,真机却很稳定能够竞争成功。
我写了个POC,binder_buffer的debugid为126800,对应的data为0x7167642100。client主线程为4017:4017,发送BC_TRANSACTION的线程为4017:4018,server线程为233:3081。binder日志如下:

[ 9397.842620] binder: 4017:4017 write 12 at 0000007167642100, read 0 at 0000000000000000
[ 9397.842658] binder: 4017:4017 BC_FREE_BUFFER u0000007167503c08 found buffer 126800 for finished transaction
[ 9397.842669] binder: 4017 buffer release 126800, size 20-0, failed at           (null)
[ 9397.842713] binder: 4017:4017 wrote 12 of 12, read return 0 of 0
[ 9397.844505] binder: 4017:4017 write 12 at 0000007167642100, read 0 at 0000000000000000
[ 9397.844514] binder: 4017:4017 BC_FREE_BUFFER u0000007167503c08 no match
[ 9397.844522] binder: 4017:4017 wrote 12 of 12, read return 0 of 0
[ 9397.846759] binder: 4017:4018 write 68 at 0000007164a14100, read 256 at 0000007164a14000
[ 9397.846784] binder: 4017:4018 BC_TRANSACTION 126804 -> 233 - node 126776, data 0000007164a15000-0000000000000000 size 128-0-0
[ 9397.846820] binder: 4017:4018 BR_TRANSACTION_COMPLETE
[ 9397.846830] binder: 4017:4018 wrote 68 of 68, read return 8 of 256
[ 9397.846844] binder: 4017:4018 write 0 at 0000007164a14100, read 256 at 0000007164a14000
[ 9397.846911] binder: 233:3081 BR_TRANSACTION 126804 4017:4018, cmd -2143260158 size 128-0 ptr 00000000e6482058-00000000e64820d8
[ 9397.846922] binder: 233:3081 wrote 12 of 12, read return 72 of 256
[ 9397.847133] binder: 233:3081 write 68 at 00000000e4805900, read 256 at 00000000e4805800
[ 9397.847148] binder: 233:3081 BC_REPLY 126805 -> 4017:4018, data 00000000e4d951c8-0000000000000000 size 20-0-0
[ 9397.847166] binder: 233:3081 BR_TRANSACTION_COMPLETE
[ 9397.847175] binder: 233:3081 wrote 68 of 68, read return 8 of 256
[ 9397.847230] binder: 233:3081 write 12 at 00000000e4805900, read 256 at 00000000e4805800
[ 9397.847242] binder: 233:3081 BC_FREE_BUFFER u00000000e6482058 found buffer 126804 for finished transaction
[ 9397.847253] binder: 233 buffer release 126804, size 128-0, failed at           (null)
[ 9397.847595] binder: 4017:4018 BR_REPLY 126805 0:0, cmd -2143260157 size 20-0 ptr 0000007167503c08-0000007167503c20
[ 9397.847607] binder: 4017:4018 wrote 0 of 0, read return 72 of 256

看时间是可以知道BC_TRANSACTION到BC_REPLY的时间差大概是847148 - 846784 = 364us,但这个时间是动态变化的,所以很好奇exp里的usleep为什么会是进入竞争窗口的依赖条件,而且能达到这么高的成功率?
2019-11-20 19:32
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
25
为什么usleep(450),这个因为线程2通过binder进程间通信,让mediaserver执行BC_REPLY需要一段时间,根据自己的机器情况调整这个值。总之是要形成竞争,看打印的日志动态调整这个值,另外竞争是多次的,不是每次都成功,有一个竞争成功就可以了。如果你发现日志,没有形成竞争关系,你就需要调整这个值。
2019-11-21 09:24
0
游客
登录 | 注册 方可回帖
返回
//