笔者作为初入安卓内核漏洞利用分析的从业者,自 CVE-2017-8890 这个漏洞被曝之后不久就开始研究其成因、原理、触发以及利用。至今遇到了无数问题,也解决了无数问题,于是记下这篇文章以做小结,一来对这段时间的工作学习做一个归纳总结,二来希望能对同样对安卓内核漏洞感兴趣的朋友有一些细节上的帮助。
+ 编号:CVE-2017-8890
+ 类型:double free
+ 位置:/net/ipv4/inet_connection_sock.c
+ 描述:
分析一个漏洞的原理,最直接的方法是从补丁入手。
CVE-2017-8890 的补丁如下所示:
可以看到这个补丁非常简单,只添加了一行代码,作用是将 inet_sk(newsk)->mc_list 置为 NULL。再结合漏洞类型为 double free,很容易得知应该是释放流程中对 mc_list 这个结构体的处理不当,导致了这个漏洞产生。那么这里比较关心的问题如下:
+ 这个对象是什么?
+ 对象在哪里产生?
+ 对象在哪里释放?
+ 为什么会产生漏洞?
通过源码分析和搜索引擎可以知道,mc_list 这个对象代表的是组播列表。其原型如下:
既然这个结构体是组播列表,那么很容易得知,当创建组播,加入组播的时候,很可能就会创建这个结构体。
通过前面的推测,加上内核源码分析,能够得出如下调用链,将会创建这个结构体。
用户态:
内核态:
知道了对象,创建流程,通过源码分析也能够找到释放的调用链。
用户态:
内核态:
PS:这里不得不说一下,我很佩服挖到这个漏洞的大佬,但是 【ADLab原创首发】“Phoenix Talon”in Linux Kernel —潜伏长达11年之久的内核漏洞 的两次对象释放写在不同的位置很误导人。之所以能够看到两次不同的释放,是因为 RCU 系统的存在,ip_mc_drop_socket 这个函数导致释放操作,真正的释放在 __rcu_reclaim。软中断是由于时钟中断导致,都是 RCU 释放流程中的正常操作。两次释放都在同一个点,都是由于用户态 close 导致的。
那么问题的关键来了,为什么会产生这个漏洞。
在搜集信息的过程中我们已经知道了这个漏洞是一个 double free,既然是 double free,那必然是一次创建,两次释放。但是从上面对象创建和释放的流程来看,并不能找到两次释放的点。
这个时候,漏洞描述中的一句话给出了分析方向:
在 accept 的时候,子对象会从父对象复制一份 mc_list。
但如果是复制的话,对象应该也会复制一份,那么对子对象和父对象都进行释放,应该是不会产生漏洞的。带着这样的疑问对源码进行了分析之后得到答案:
首先 mc_list 是 sock 对象的一个成员,并且是由 sock 中的指针所指向的对象
accept 的时候会把 sock 对象拷贝一份而不是 mc_list
由以上两点就能够解释漏洞为何产生了 —— 多个对象拥有了指向同一个对象的指针。
那么这个漏洞已经不是 double free 了,甚至可以是 X free,因为只要 accept 多次,那么就会有多个对象指向同一个 mc_list。
从上面的分析中我们已经得到了几个触发漏洞的关键点:
+ 如何创建对象
+ 如何释放对象
+ 为何产生漏洞
那么 POC 的构建已经是轻而易举了,伪代码如下:
这里需要注意的是 accept 要对应 connect。
因为利用涉及到太多的技术细节,所以这里主要讲思路,具体还是要自己去调试分析才能知道明白,要知道,只有在调试器下,才是没有秘密的。
目前,我们拥有的条件如下:
+ 能够触发漏洞
+ 知道这个漏洞是 double free
目的如下:
+ 成功利用漏洞,达到任意地址读写
而漏洞利用就是在拥有的条件之下,不断想方设法提升当前权限,以达到最终目的的过程。
+ 创建漏洞结构体
+ 第一次释放漏洞结构体
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-2-2 10:05
被admin编辑
,原因: 图片本地化