首页
社区
课程
招聘
[原创]cve-2015-6620学习总结
发表于: 2018-5-11 21:43 8063

[原创]cve-2015-6620学习总结

2018-5-11 21:43
8063

想学习下android漏洞方面的知识,搜了下发现Flanker Edward在知乎上有个回答,提到了binder的经典漏洞cve-2015-6620,所以就从这个漏洞开始学习。作者提供了poc以及文档,这篇笔记主要记录下学习中遇到的问题,以及自己的一些理解。

第一次调试android漏洞,搭建环境花了些力气,主要有如下环境,推荐安装pead-arm和shadow这两个gdb插件。

这是android平台上的binder方面的漏洞,所以涉及一些android底层的知识需要学习下。

cve-2015-6620包含两个漏洞,编号分别为24123723和24445127。主要分析的是24445127 MediaCodecInfo越界访问,因为这个漏洞可以利用的点更多些。漏洞存在于MediaCodcList服务。该Binder服务提供了一个getCodecInfo的功能,存在漏洞的代码如下:

从Parce中读取从客户端传来的索引index,然后调用在服务端的实现的getCodecInfo。看下在MediaCodecList中实现的getCodecInfo

可以看到直接调用了vector的itemAt函数,并未进行任何边界检查。而index是我们作为客户端程序可以控制的,这个地方就存在一个越界访问的漏洞。

根据漏洞的成因,我们现在有这样一个能力:可以越界访问Binder服务所在进程中的一个vector<sp<MediaCodecInfo>>,但是只能读取不能写入。漏洞的作者利用这样一种能力可以实现任意地址读取和pc寄存器的控制,很是神奇。主要分析下pc控制的原理。在分析poc原理前,需要了解相关对象在内存的布局,如下图所示:

一个越界读可以造成pc的控制,关键在于getCodecInfo的调用: const sp\<MediaCodecInfo\> info = getCodecInfo(index);

上面的代码是用getCodecInfo函数的返回新建了一个info对象,这就会调用info的拷贝构造函数。info的类型为sp,sp的拷贝构造函数如上所示。可以看看getCodecInfo的汇编版本,像这样返回对象的函数,一般会把R0指向返回对象保存的地址。

可以看到会将vector的内容读取到R0中,如果R0不为零,会调用incStrong, 代码如下:

汇编代码版本,可以清楚看到存在虚函数的调用:

梳理一下就是,越界读取的内容放入R0,然后进行如下操作:

也就是说如果我们在内存中伪造了合适的MeidaCodecInfo,并且将指向该伪造的MediaCodecInfo的指针放入vector<sp<MediaCodecInfo>>存储区的后面,这样我们就可以通过越界访问,读取到指向该伪造的MediaCodecInfo的指针,进而控制pc。我们可以在内存中伪造如下的MediaCodecInfo:

最终poc运行成功,mediaserver运行到我们指定的位置:0x61616161

要成功的运行poc实现漏洞利用的目的,要进行两次堆喷射,第一次是将我们伪造的MediaCodecInfo喷射到内存中,第二次是将我们伪造的MediaCodecInfo的地址喷射到vector<sp<MediaCodecInfo>>的存储区的后面,这样可以通过越界读取,来触发漏洞。
但是遇到了如下问题:

1.作者的poc中,硬编码了一个地址0xb3003010,就是在作者的测试机器上,作者喷射的伪造的MediaCodecInfo有很大概率会落在这个地址上。作者说之所以是0xb3003010而不是0xb3003000是因为数据前面还有0x10字节的元数据,但是我们知道jemalloc中存放数据的region和run都不包含元数据,那么这个元数据是哪里来的?

先看下是如何堆喷射的,作者使用IDrm.provideKeyResponse进行堆喷射的,服务端在拿到response后,最终会调用Session.provideKeyResponse处理:

可以发现喷射的数据最终是保存在android::Vector中的,通过查看源码发现:android::Vector的数据是保存在SharedBuffer中的。0x10字节保存的就是SharedBuffer的私有变量

2.第一次堆喷射需要将指向伪造的MediaCodecInfo的指针喷射到vector<sp<MediaCodecInfo>>的存储区的后方,但是我在运行作者poc的时候,越界读取很少可以命中,所以就想如何可以提高命中率。

作者的方法是:vector的存储区肯定是jemalloc分配的,肯定是落在某个大小的region内,所以作者首先计算出这个大小,然后后面堆喷射时,喷射出大量相同大小的region,这样后面越界读取就有很大概率命中。所以关键是如下步骤:

通过调试发现vector<sp<MediaCodecInfo>>的存储区所在region大小和作者中poc给的一致,但是在调试时发现喷射的payload并没有落在大小为160的region内,而是在0x100的region内。

原因就是payload在mediaserver中是保存在Vector中的,Vector在分配空间时会多分配一些,所以大小为160的payload,最终会放置在大小大于160的region中,通过调试,我把payload大小改为96就可以保证分配在160的region中。

修改后,运行poc后,内存布局如下图所示:

3.作者并未说明是如何找到0xb3003010这个地址的,存在这样一个地址的依据是什么呢?

查了一些关于android堆喷射的资料,都提到jemalloc相比之前的dlmalloc更脆弱些,具体表现在如下方面:

上面的堆地址熵较小表现在:32位ARM系统上的ASLR算法的实现很简单,ASLR会将所有的模块随机向下移动几页,范围在0~255页,代码如下,mmap_rnd_bits可以通过/proc/sys/vm/mmap_rnd_bits 来改变。

可以看到随机移动的范围不大,而进程的各个模块在大范围的是相对固定的,比如在我的机器上,堆分配的空间基本落在0xaf000000 - 0xb6000000 之间,当分配的内存远大于255页时,就基本可以找到一个稳定的地址来放置payload,可以粗略计算下:

作者构造的payload在binder服务端,最终是保存在Vector中的,Vector会多分配一些空间。在我的机器上最终分配的空间大小为6144字节,放在大小为0x1800的region内,都是放在大小为0x3000的run内,每个run可以放置两个这样的region,并且run是页对齐的。也就是说分配两次payload就占用了3页大小空间,作者的poc一共分配了0x1200次,理论讲会一共分配了6912页,当然实际中会存在回收后再利用的情况,在我的机器上实际上分配了3000多页,这是远远大于随机移动的0~255页。所以可以找到这样一个相对稳定的地址。

作者并没有给出explicit,但是提到可以用 CVE-2015-1528 exp的思路,后续会继续学习下这个思路,有成果了就补上。小弟刚开始学习漏洞这块,有错误恳请大佬们指正。

漏洞作者给的文档以及poc: https://github.com/flankerhqd/mediacodecoob

adb+gdb : https://wladimir-tm4pda.github.io/porting/debugging_gdb.html

binder学习:https://blog.csdn.net/universus/article/details/6211589

jemalloc: https://blog.csdn.net/koozxcv/article/details/50973217

shadow jemalloc 调试: https://blog.csdn.net/hl09083253cy/article/details/79147625

shadow 安装:https://github.com/CENSUS/shadow

heap fengshui: https://bbs.pediy.com/thread-55879.htm

ASLR:http://drops.xmd5.com/static/drops/papers-14181.html

 
 
 
 

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

最后于 2018-5-11 21:45 被glider菜鸟编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (10)
雪    币: 699
活跃值: (444)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
2
赞,你是在什么手机上调的
2018-5-13 15:06
0
雪    币: 182
活跃值: (555)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
sakura零 赞,你是在什么手机上调的
谢谢,模拟器上调试的
2018-5-13 18:11
0
雪    币: 62
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
2018-5-14 10:12
0
雪    币: 182
活跃值: (555)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
toToC
,谢谢
2018-5-14 18:21
0
雪    币: 3136
活跃值: (97)
能力值: ( LV9,RANK:165 )
在线值:
发帖
回帖
粉丝
6
请问下,poc.cpp怎么编译的?
2018-5-15 17:22
0
雪    币: 182
活跃值: (555)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
demoLin 请问下,poc.cpp怎么编译的?
放在源码目录内
LOCAL_PATH  :=  $(call  my-dir)
include  $(CLEAR_VARS)
LOCAL_MODULE  :=  mediapoc
LOCAL_MODULE_TAGS  :=  optional
LOCAL_SRC_FILES  :=  mediapoc.cpp
LOCAL_CFLAGS  +=  -march=armv4
LOCAL_SHARED_LIBRARIES  :=  libbinder  libutils  libmedia  libstagefright_foundation
include  $(BUILD_EXECUTABLE)
最后于 2018-5-16 09:17 被glider菜鸟编辑 ,原因:
2018-5-16 09:17
0
雪    币: 3136
活跃值: (97)
能力值: ( LV9,RANK:165 )
在线值:
发帖
回帖
粉丝
8
glider菜鸟 demoLin 请问下,poc.cpp怎么编译的? 放在源码目录内LOCAL_PATH&nbsp; :=&nbsp; $(call&am ...
你好,再问一下LOCAL_SHARED_LIBRARIES的查询路径是什么?我用ndk-build总是找不到依赖模块
2018-5-16 11:35
0
雪    币: 4366
活跃值: (353)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
9
mark一下,学习。
2018-5-21 22:20
0
雪    币: 53
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
学习
2018-5-22 10:18
0
游客
登录 | 注册 方可回帖
返回
//