前段时间特别火的blueborne对于Android影响还是蛮大的,这个系列的漏洞中有三个是在Android系统上,这次分析的是信息泄漏漏洞CVE-2017-0785,这分析的过程中360的博客和博客中提供的POC帮助巨大,特别感谢。并且在360的博客中已经对这个漏洞的成因有了比较详细的解释,因此就不在本文中做太详细的分析,本文主要分析我在调试过程中遇到的问题。
0x01 漏洞简述
CVE-2017-0785的漏洞代码在Android蓝牙实现中,代码位置 bt/stack/sdp/sdp_server.cc
这个漏洞触发需要蓝牙通信包多次交互,前面360的博客讲的很清楚,这里就不具体分析了。这个漏洞的关键是
- (I) cont_offset是越界读的关键,越界读取发生在5处对rsp_handles的读取
- (II) cont_offset可以被控制,但是有检查,就是1处,因此需要把p_ccb->cont_offset变大
- (III)每次p_ccb->cont_offset只会增加cur_handles,cur_handles其实就是代表这个一个包里要发送的handles数量
- (IIII) cur_handles 的值是 min(rem_handles,每个蓝牙包最多能放的handles的数量),rem_handles是剩余要发送的handles数量
0x02 漏洞的调试
漏洞代码对应的so是,bluetooth.default.so,在Android系统中处理蓝牙通信的com.android.bluetooth会加载这个so。因此,IDA远程调试attach到这个进程上去。下面关键的问题就是下断了。我测试用的手机中的bluetooth.default.so没有process_service_search符号,所以我用字符串的方式来查找这个函数的地址。查找process_service_search的上层函数是sdp_server_handle_client_req
这个函数中有一个特征字符串“SDP - server got unknown PDU: 0x%x”,在IDA中查找到这个字符串,
再向前查找到判断等于2的的的分支可以找到需要分析的关键函数。
这里memset就是在对rsp_handles进行清零操作,W1存放的就是rsp_handles的首地址,因此在调试的过程中主要需要关注W1中的数据。
ps:由于这里好几个函数存在没有return的分支,导致IDA对函数的识别不是很准,把好几个函数揉在了一起,需要花点时间手工分析一下。
0x03 POC改进
我在测试的时候发现在360博客中提供的poc获取的数据有一点小问题,这一部分我解释一下poc,并说一点我的看法。
poc的代码并不复杂,大致的过程就是不断发包使p_ccb->cont_offset的值越来越大,构成越界读
首先poc通过l2cap_set_mtu设置了包的mtu为48
根据前面android系统中的process_service_search处理代码
可以得到一个包里最多可以传送(48-12)/4,即9个handles,解释一下,包的总大小48字节,12个字节用于包自身一些结构数据,因此有36个字节可以用于发送需要发送的handles,handles是uint32类型,每个占4个字节,所以一个包最多可以放9个。
这12个字节的包结构数据在process_service_search最后构造包的时候可以看到
因此,来查看poc中处理接收数据的部分,我认为有一些不合理
这个地方将接收到的数据偏移12的位置,拷贝了recv_size-12-3的数据出来,实际上根据上面的分析,包结构数据前面9字节后面3字节,一共12。应该改为如下代码更为合理
最后,用改动过的poc结合前面的调试,测试读取出来的内存数据。
首先通过W1确定rsp_handles的地址是0x0000006FF324B5A0,位于当前栈上
在最后一次发送之前查看0x0000006FF324B5A0后面的数据
获取到的数据打印结果如图
因为没有进行字节序的转换,所以数据显示上不太一致,可以看出图中红框中的内容就是栈中0x0000006FF324B618地址处数据字节序转换后的样子。
事实上在process_service_search中的UINT*_TO_BE_STREAM中就进行了字节序转换,只要进行一下转换就可以了。测试读取了0x100个字节,已经可以拿到libc和bluetooth.default.so中符号的地址,因为alsr的偏移是针对模块的,也就意味着,在知道机型系统版本的情况下这两个模块其他符号的地址也可以确定了。