首页
社区
课程
招聘
[原创] CVE-2017-7533 漏洞利用
发表于: 2019-2-12 21:10 12317

[原创] CVE-2017-7533 漏洞利用

2019-2-12 21:10
12317

一、测试环境:

Android模拟器Nexus_6P_API_25@kernel 3.18


二、漏洞介绍

代码位于fs/dcache.c



由于dentry->d_name.name和filename是同样的值,在注释[1]和注释[2]之间,如果执行了注释[4],在strcpy时会导致heap overflow。

具体poc可以参考心许雪的这篇文章《[原创](Android Root)CVE-2017-7533 漏洞分析和复现》


对于长文件名,两个线程同时跑,由于竞争,在strcpy(event->name, file_name)也会发生heap overflow。


在实际的调试中,file_name的值大于old_name的值0x10字节,两者地址有重叠。如果old_name被堆喷射重新占位后的大小过大,在strcpy时会发生heap overflow。


三、如何利用

由于android 8.0已经引入了PAN机制,内核态不能访问用户态的数据,所以传统的通过覆盖ptmx结构体指针,从而实现任意地址写,变的不可能。或者通过挟持指针指向kernel_setsockopt,修改addr_limit,从而通过管道实现任意地址写,也变的不可能。因为他们都需要从用户态读取数据。

参考ThomasKing在BlackHat的文章asia-18-WANG-KSMA-Breaking-Android-kernel-isolation-and-Rooting-with-ARM-MMU-features。使用内核镜像攻击,可以绕过PAN机制。原理可以参考Geneblue《KSMA -- Android 通用 Root 技术》,简单的说需要利用地址写漏洞,向内核的L1页表写入一个block,这个block可以映射内核物理地址开始到内核地址+1G的地址范围。


对于我的操作系统,内存布局如下:

虚拟地址                                物理地址

0xffffffc000000000                 0x40000000

0xffffffc060000000                 0xA0000000

我们通过向内核页表中写入block,形成如下映射,由于内核地址空间是在物理地址0x40000000~0x80000000之间,这样我们可以在用户态通过0xffffffc200000000~0xffffffc240000000访问整个内核地址空间,具体细节后面漏洞利用会再讲。

虚拟地址                                物理地址

0xffffffc200000000                 0x40000000

0xffffffc240000000                 0x80000000


现在我们可以任意的修改内核地址空间,为了实现root,参考asia-18-WANG-KSMA-Breaking-Android-kernel-isolation-and-Rooting-with-ARM-MMU-features做法,修改setresuid。

有人可能会有这样的问题,如果有了任意地址写,不就已经可以实现root了么?是的,不过针对CVE-2017-7533来说,写的地址并不任意,只能向一个内核地址写入内容


那么,刚刚我们才说过,这是一个heap overflow漏洞,又如何变成向一个内核地址写入内容呢?

可以参考Retme the art of exploiting unconventional use-after-free bugs in android kernel,通过heap overflow覆盖iovec的addr为内核地址,从而实现向一个内核地址写入内容。

系统调用readv,跟踪代码会执行到:


此时如果不调用write函数,readv函数将会睡眠等待至write函数发生。


如果此时通过heap overflow覆盖了iov_base为内核态地址,当write函数发生时,会向kernel_addr写入数据,而且此时并没有校验iov_base是否为用户态,前面已经校验过了。



四、漏洞利用

1、堆风水

如何使strcpy(event->name, file_name) 可以覆盖iov_base,向其写入kernel_addr。

首先我们看一下我们要布局的对象的大小。

iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); //nr_seg需要大于8,我这里选择10,iov对象的大小是160个字节,从kmalloc-192中分配。如果要覆盖iov,下面的event,file_name就得选比较大的文件名,所以这个漏洞,不能通过短文件名触发。


event = kmalloc(alloc_len, GFP_KERNEL);  //分配sizeof(struct inotify_event_info)+strlen(file_name)+1内存 ,44+144+1=189字节,从kmalloc-192中分配。


kfree_rcu(old_name, u.head) old_name也是144个字节,从kmalloc-192分配,这里是释放。

sendmsg堆喷,172个字节,从kmalloc-192分配。


为什么是172个字节?

sizeof(struct inotify_event_info) = 44个字节,event总的长度是192个字节,如果想覆盖iov,那么file_name被堆喷重新占位后的大小应该是192- 44 + 8(iov_addr的字节数)=156,由于file_name的值大于old_name的值16个字节,所以sendmsg应该堆喷156+16个= 172字节。


堆风水步骤:

1)首先起大量线程分配iov对象(通过readv函数,会阻塞线程,所以需要大量线程)。

2)每隔一个对象释放iov,形成空洞。

3)通过以下竞争,event落在空洞上,并且旁边就是另一个iov对象:


4)堆喷占位old_name,strcpy覆盖旁边iov对象iov_addr


2、向内核页表写入block

前面我们说了,向内核页表写入block的目的是在用户态通过0xffffffc200000000~0xffffffc240000000访问整个内核地址空间。

内核已有的映射:

虚拟地址                                物理地址

0xffffffc000000000                 0x40000000

0xffffffc060000000                 0xA0000000

虚拟地址                                物理地址

0xffffffc200000000                 0x40000000

最后于 2019-2-13 09:32 被jltxgcy编辑 ,原因:
收藏
免费 6
支持
分享
打赏 + 6.00雪花
打赏次数 2 雪花 + 6.00
 
赞赏  Imyang   +1.00 2019/02/18 666
赞赏  Editor   +5.00 2019/02/14 精品文章~
最新回复 (11)
雪    币: 13944
活跃值: (17218)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
2
请问LZ,安卓的模拟器叫什么名字,还是说名字就叫安卓模拟器??
2019-2-12 22:11
0
雪    币: 4361
活跃值: (348)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
3
 收藏学习~
2019-2-12 22:27
0
雪    币: 15
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
每次看到这些代码,我都只默默的看着,从上往下,看完后抽支烟,这是说的什么啊,我完全看不懂啊
2019-2-12 23:24
1
雪    币: 47
活跃值: (418)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
5
收藏学习,厉害了
2019-2-13 00:04
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
pureGavin 请问LZ,安卓的模拟器叫什么名字,还是说名字就叫安卓模拟器??
Nexus_6P_API_25
2019-2-13 09:32
0
雪    币: 1149
活跃值: (873)
能力值: ( LV13,RANK:260 )
在线值:
发帖
回帖
粉丝
7
2019-2-13 11:11
0
雪    币: 24478
活跃值: (62819)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
8
感谢分享!
2019-2-13 13:53
0
雪    币: 199
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
请问swapper_pg_dir要从哪里知道呀
2019-4-9 11:54
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
10
gy21 请问swapper_pg_dir要从哪里知道呀
如果是内核源码编译刷机,在内核源码目录下会生成System.map,里面有swapper_pg_dir和其他内核函数的虚拟地址。
2019-4-14 09:33
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
你好 我在单核的模拟器上并没有成功触发poc。请教一下 这种race的bug是否需要一个多核的模拟器来调试?启动参数如何设置呢?qemu的-smp参数貌似与avd不兼容
2019-12-23 16:03
0
雪    币: 39
活跃值: (52)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
mark
2020-3-11 11:42
0
游客
登录 | 注册 方可回帖
返回
//