首页
社区
课程
招聘
[原创] CVE-2017-8890 漏洞利用(root nexus6p@kernel 3.10)
发表于: 2019-1-29 12:03 9599

[原创] CVE-2017-8890 漏洞利用(root nexus6p@kernel 3.10)

2019-1-29 12:03
9599

2018.08 CVE-2017-8890 漏洞利用 之 nexus6p@kernel 3.10

目录

 

由于CVE-2017-8890属于linux kernel 4.10版本之前网络子系统中的问题,因此Android也受影响。hardenedlinux上曾收集了Jeremy Huang的部分exploit,经过测试在nexus6p上可以控制PC指针。本文内容多是别人的经验总结,对该exploit做简单分析并基于该exploit完成后续的利用工作。

 

###测试环境

* nexus6p 
* 自编译的kernel version 3.10

利用过程

1. control PC
2. patch addr_limit
3. search init task_struct's init_head (has two pointers) by pushable_tasks 0x8c
4. search target process (init and exp) and get cred address by cpu_timers[2]
5. patch exp cred uid,gid,suid..... cap......    and get root
6. patch exp security's osid, sid and selinux_enabled, selinux_enforcing
7. system("/system/bin/sh")

一、控制PC

控制PC的过程Jeremy的exploit已经完成了。利用的思路在Freebuf上云图信安的文章[1]已经详细分析过了。这里简单阐述一下,server端首先通过setsockopt 中的MCAST_JOIN_GROUP参数初始化一个带有vulnerable obj ip_mc_socklist的socket,设置server的 socket监听后,创建client线程connect两次,因此server端accept返回,在内核中将父socket复制,产生了两个带有vulnerable obj ip_mc_socklist的子socket。释放这两个socket时,ip_mc_socklist obj也会被释放两次。释放ip_mc_socklist obj的过程是在ip_mc_drop_socket中完成的,调用kfree_rcu注册回调函数,等待回调函数触发时来真正的释放这个obj。当rcu宽限期结束后,时钟中断触发时会调用rcu注册的回调函数。这时会kfree两次,造成double free。
Alt text
Alt text

 

注意:ip_mc_socklist obj 第二次free之前,由于kernel中的内存已经被释放了,正常不堆喷的情况下,可能会被其它的程序占位。在ip_mc_drop_socket中的ip_mc_leave_src中会对这个obj中的其它指针解引用,因此在ip_mc_leave_src中crash也是正常的。本质上crash的原因都是由于double free造成的。

 

了解了ip_mc_socklist obj 真正的释放过程后,就可以理解通过double free来控制PC的过程了。通常double free的利用有两种思路:一种是利用堆管理器的特性实现double free到代码执行,另一种就是通过占位把double free转化成UAF来使用。这里使用的是第二种。由于该漏洞的两次free的时机都是可控的,因此可以在第一次真正的kfree之后,通过堆喷射来占位释放的obj。通过构造占位的obj中的数据,控制ip_mc_socklist.rcu中的func(回调函数地址)即可劫持PC或控制next_rcu将ip_mc_socklist链中的next_rcu劫持到用户态再修改func指针来劫持PC。

 

利用思路二中直接控制func:之前在ubuntu上动态调试时,我尝试在ip_mc_drop_socket的kfree_rcu之前用gdb手工修改内存中的func几十次后,发现依然不能劫持PC,感觉对于回调函数保存和触发过程还是不熟悉。
利用思路二中劫持next_rcu:由于不存在SMAP或者是PAN,劫持next_rcu到用户态后,就可以为所欲为了。做一个循环不停地占位func,可以保证回调函数触发时,func是我们控制的值。

 

漏洞分析过程还可以参考之前的文章。

 

在Jeremy的exploit中,还用到了bind_on_cpu这个函数。一开始不明白这个函数的作用,讲与之相关的调用删除后,有大概率会出现
kernel page request error的log。

[  467.451776] Unable to handle kernel paging request at virtual address 0c00011f
[  467.451810] pgd = ffffffc00007d000
[  467.451817] [0c00011f] *pgd=000000000e90b003, *pmd=00000000b3371003, *pte=02e00000a8469713
[  467.451846] Internal error: Oops: 96000006 [#1] PREEMPT SMP
[  467.451865] CPU: 0 PID: 3 Comm: ksoftirqd/0 Tainted: G        W    3.10.73-g2c63035e12a8-00029-gc0f56dc0113e-dirty #3
[  467.451874] task: ffffffc00e9a1580 ti: ffffffc00e9c0000 task.ti: ffffffc00e9c0000
[  467.451902] PC is at rcu_process_callbacks+0x2ec/0x53c
[  467.451910] LR is at rcu_process_callbacks+0x30c/0x53c
[  467.451916] pc : [] lr : [] pstate: 80000145
[  467.451923] sp : ffffffc00e9c3ca0
[  467.451929] x29: ffffffc00e9c3ca0 x28: 000000000c00011f
[  467.451941] x27: ffffffc00e9c0000 x26: ffffffc0450d0648
[  467.451953] x25: 0000000000000005 x24: 0000000000000003
[  467.451965] x23: ffffffc0c0cccbd0 x22: ffffffc0010ff12e
[  467.451976] x21: ffffffc0c0cccba8 x20: ffffffc00166fd4f
[  467.451988] x19: ffffffc0017844c0 x18: 0000000000000000
[  467.452000] x17: 0000007bc75fe360 x16: ffffffc00031c978
[  467.452011] x15: 00000000004f1118 x14: 0ffffffffffffffe
[  467.452023] x13: 0000000000000030 x12: 0101010101010101
[  467.452034] x11: 7f7f7f7f7f7f7f7f x10: 0000000000000000
[  467.452046] x9 : ffffffbc01148700 x8 : 0000000000000040
[  467.452057] x7 : ffffffc0c4e4de80 x6 : 0000000000000004
[  467.452068] x5 : 0000000000000000 x4 : 0000000000000001
[  467.452080] x3 : 0000000000000101 x2 : 0000000000000101
[  467.452091] x1 : ffffffc00e9c0000 x0 : 000000000c00011f

最终,使用Jeremy的exploit劫持PC后,就可以开始后续利用了。

二、patch addr_limit

addr_limit代表当前thread可以访问的地址空间大小,如果patch了该thread的task_struct的addr_limit为-1,该thread就可以访问全部地址空间的数据了。目前了解的patch addr_limit有两种方式。第一种在控制了一个寄存器和PC后,参考PXN的研究与绕过@莫灰灰的文章中,构造第一段jop来泄漏出SP到用户态。拿到SP,屏蔽低位后等于拿到了thread_union中的thread_info的地址,也就拿到了addr_limit的地址。用类似STR的指令将addr_limit的地址放在用户态后,再构造jop去patch addr_limit。这要求我们可以控制PC两次,或者能一次jop完成这些操作。

 

在实际利用中,找了很久的gadget勉强可以泄漏出SP到用户态。如果想要控制一次PC的情况下就使用jop来完成SP的泄漏,计算addr_limit地址,patch addr_limit,也是可以的。只不过泄漏SP之后的jop比较难找,因此就转向了第二种方法。
Alt text
Alt text

 

第二种方法是360冰刃实验室在mosec2016提出的。利用了来自内核的馈赠:set_fs()。跟踪set_fs()的实现可以看到该函数完成了patch addr_limit的操作。
Alt text

 

Alt text


[注意]看雪招聘,专注安全领域的专业人才平台!

最后于 2019-1-29 12:24 被心许雪编辑 ,原因:
收藏
免费 7
支持
分享
打赏 + 5.00雪花
打赏次数 1 雪花 + 5.00
 
赞赏  aabiaobiao   +5.00 2019/01/31 非常想跟老哥认识认识
最新回复 (12)
雪    币: 438
活跃值: (239)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
2
赞。学习一下android上面的利用
2019-1-29 14:14
0
雪    币: 123
活跃值: (1675)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
2019-1-29 15:15
0
雪    币: 4366
活跃值: (353)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
4
ID蝴蝶 赞。学习一下android上面的利用[em_63]
谢谢~ 一起学习
2019-1-29 23:52
0
雪    币: 4366
活跃值: (353)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
5
许文伟爱工作 [em_63][em_60]
感谢支持。
2019-1-29 23:53
0
雪    币: 6573
活跃值: (3983)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
6
2019-1-30 10:45
1
雪    币: 94
活跃值: (228)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
厉害
2019-1-30 11:01
0
雪    币: 47
活跃值: (418)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
8
赞赞赞
2019-1-30 11:07
1
雪    币: 29
活跃值: (420)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
9
感谢分享 赞
2019-1-30 11:19
1
雪    币: 53
活跃值: (286)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
解释的很详细,赞!

"当前的exp的context已经是init的了,比较神奇的时候调用某些命令,如id看到的context是toolbox的。"
这是因为selinux策略toolbox.te中有定义
init_daemon_domain(toolbox)
即init domain的进程执行toolbox类型的可执行文件,会自动域转到toolbox domain上。
2019-1-30 12:07
3
雪    币: 4366
活跃值: (353)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
11
netsniffer 解释的很详细,赞! "当前的exp的context已经是init的了,比较神奇的时候调用某些命令,如id看到的context是toolbox的。" 这是因为selinux策 ...
学习了。thanks!
2019-1-30 14:02
0
雪    币: 275
活跃值: (259)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
12
2019-1-30 20:56
0
雪    币: 444
活跃值: (3211)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
13
BLX X5  跳过setfs 后ret不会蹦吗?  奇怪, ummmmm... X30 由 ret上一行指令决定?  那x86 平台用的是call 调的指针, 这下返回时总该蹦了吧 
最后于 2019-8-26 23:41 被酒肉和尚编辑 ,原因:
2019-8-26 23:27
0
游客
登录 | 注册 方可回帖
返回