QQ手机浏览器“虫洞漏洞”挖掘分析全过程

DorotheaSks 4年前
   <h3><strong>0x1.引子</strong></h3>    <p>前段时间盘古的同学发现了QQ手机浏览器的“虫洞漏洞”,在这个漏洞的挖掘分析过程中,盘古的同学和我们针对这个漏洞做过内部技术交流,我们也同步分析出了该漏洞,最终由于是盘古的同学第一个发现,所以由盘古的同学报告给腾讯。目前该漏洞已经修复,我们和大家分享一下这个漏洞的分析和挖掘全过程,供大家参考。</p>    <h3><strong>0x2.样本信息</strong></h3>    <p>下载链接:http://mb.qq.com/</p>    <p>文件名称:qqbrowser_6.9.2.2665_20820.apk</p>    <p>文件md5:64FE443F770BA9433E23D689C78DAF99</p>    <p>versionCode: ‘6922665’</p>    <p>versionName: 6.9.2.2665</p>    <p>云盘备份地址:https://yunpan.cn/cM8JVT39xQnhw  访问密码 d7d6</p>    <h3><strong>0x3.特征定位</strong></h3>    <p>查看手机所开端口发现一处可疑端口本地未校验。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/09023b3042ecb064493d6bc2f23f4275.png"></p>    <p>所以需要对本地所有dex文件进行扫描,看看此部分功能到底是在哪里,在做什么。</p>    <p>通过搜索端口号以及判定是打开Sokcet,我们确定此处地址。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/a906e773bd106c7705ff912427ca5c41.png"></p>    <p>即确定文件所在包为:</p>    <p>assets/dex/com.tencent.mtt.sniffer.jar</p>    <h3><strong>0x4.代码深入</strong></h3>    <p>现在我们就可以继续往下进行分析了。</p>    <p>我们用jeb查看一下java代码。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/a47bad25d93dd6ea34ed7d0aabcdd56d.png"></p>    <p>既然g.b是获取的端口8786数字,那么g类很可能就是初始化socket的类,所以我们按照代码逻辑往下看一下这个g类,发现这里this.i的数值是new j(this.a),而这个j类则包含很多数据。</p>    <p>如下图所示:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/75a927d58fcb197d25614950f1f851b9.png"></p>    <p style="text-align: center;">第一个红框是方法名,处理申请的访问链接流程的。</p>    <p>第二个红框是请求的网址,根据不同的请求执行不同的功能。</p>    <p>第三个红框就是执行的功能,在代码下面有很多类似结构。</p>    <p>这里我们先看一下/getWifiInfo这个请求。</p>    <p>在j.a(this.a,arg13)方法我们往后跟一下。</p>    <p><img src="https://simg.open-open.com/show/7adc038d40e614efaf953a7c21d57e9b.png"></p>    <p>这里有两处需要分析的地方,一处是数据处理,即请求访问协议的数据的加密与解密;一处是Message的发送,即不同的请求走不同的方法分支。我们先看第一处红框这个位置,是将数据进行处理,this.a(v2.toString)方法我们跟进去。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/8d0d31106b1fc317a4c1b4d8f7cc6b64.png"></p>    <p>可以看到执行的是e.a和e.b方法,我们看到这个,一般是可以猜测到是加解密的方法。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/b45bbe474abc4f99f5a3876d1ce18c30.png"></p>    <p>这样,我们就明显的确定是通过的3des进行的加解密处理。</p>    <p>然后密钥的获取可以直接静态分析得到。</p>    <p>密钥的获取:</p>    <p>l. <em>b</em> = b. <em>b</em> + h. <em>c</em> ;</p>    <p>b . <em>b</em> = <strong>“kM7hYp8lE69U”</strong> ;</p>    <p>h . <em>c</em> = e. <em>b</em> + d. <em>f</em> ;</p>    <p>e. <em>b</em> = <strong>“jidhlPbD9”</strong> ;</p>    <p>d . <em>f</em> = <strong>“8Pm”</strong> ;</p>    <p>密钥==” <strong>kM7hYp8lE69UjidhlPbD98Pm</strong> ”</p>    <p>在寻找密钥的过程中,我们发现访问请求的数据加密,和服务器返回的数据解密,都是通过3des加密解密,然后进行Base64编码解码处理的。</p>    <p>所以我们整理一下思路,先对刚才的getWifiInfo请求进行测试模拟。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/03fe21663051ed0a333ef99dcfbbf6bc.png"></p>    <p>流程也就是先在本地进行8786端口转发一下。</p>    <p>然后用python写一下网络请求即可,在上面截图中的url大家可以直接看到。</p>    <h3><strong>0x5.漏洞利用</strong></h3>    <p>上一条测试通过之后,我们继续往下看,有更多的协议需要分析。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/8470243652b077675a55983906f855ac.png"></p>    <p>我们这里可以看到,第一条getWifiInfo协议没有判断,直接会进行请求,而后面的请求,都是基于uuid来进行判定,如果uuid存在并且合法,那么才会进行后续请求,所以主要问题在于我们如何构造uuid并且使之合法化。</p>    <p>我们继续分析代码,也就是上图第二个红框标识的地方,如果uuid不是空,同时本地的一个hashmap中没有记录过它,那么将会往下走if的流程,所以看到这个/bind协议,我们就可以猜测,这条协议是否是绑定uuid的呢?</p>    <p>跟进去看一下this.a.a(arg12);</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/a5c96215df2e17c2d3477d9f236e85d8.png"></p>    <p>我们看到这个红框,可以发现上文中我们在跟getWifiInfo方法的时候,也跟进去了,所以我们分析一下这个是什么意思。</p>    <p><img src="https://simg.open-open.com/show/3c8c714465c77bb2df5b09089367709d.png"></p>    <p>经过代码流程的跟踪,我们到了这个类,发现这里是处理Message流程的地方。</p>    <p>当前bind走的是case 0,也就是this.a.b(arg5.obj);</p>    <p>再跟一下。</p>    <p><img src="https://simg.open-open.com/show/f85d0eeb7790555fb0af77ab1a1af0e5.png"></p>    <p>这里的是我们请求的v0_1,即需要post数据的json字符串,可以看到保证code有数值,或者qq有数值即可。</p>    <p>然后走this.a(“ok”,v0_1);是正常绑定的流程,所以我们继续跟进去。</p>    <p><img src="https://simg.open-open.com/show/91f3db17d0a6ec524c23c335829c5c7c.png"></p>    <p>看到这两个红框标识的位置,我们保证刚才传过去的字符串包含ok,而json数据中包含上面提到的code数值,以及uuid数值即可,这就是bind的过程,即绑定uuid的过程。测试一下。</p>    <p>我们简单截图一下:</p>    <p><img src="https://simg.open-open.com/show/c25e1bb32aa5a93e4fc0bbc2cbfd0214.png"></p>    <p>下面是请求访问成功的截图。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/a12e8ba9e2f200872a849f0ee9464423.png"></p>    <p>这里绑定好uuid之后,后面的请求我们按部就班地跟着分析就行,没有什么难度了。</p>    <p>比如getapplist协议,getappInfo协议。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/6baec174d76b2979eb5ca816a3c815bd.png"></p>    <p><img src="https://simg.open-open.com/show/a59fedef834e2a99776d1eda389047bb.png"></p>    <p>获取手机安装的app列表信息不算太可怕。</p>    <p>我们往下分析。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/21b07d1fd5f68de3f382f5e5f4ad6c29.png"></p>    <p>根据名称,我们推测一条是下载安装app的,另外一条是在手机上显示对话框的。</p>    <p>访问构造参数根据代码分析一下就好,这里就不贴了。</p>    <p>直接发一下测试结果。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/75c646ca87285dd11498bb3520336425.png"></p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/e9eb1b548ad4324fe8ee93981b2598db.png"></p>    <p>好了,这样就测试完毕了。因为这里下载,安装,没有走su的流程,也就是没有使用静默安装的,而是调用的系统安装页面,所以是上图所示。</p>    <h3><strong>0x6.安全建议</strong></h3>    <p>1).使用RSA加密操作,对所有的请求进行RSA加密,然后本地存储RSA公钥进行身份验证。</p>    <p>2).去除这部分命令执行功能,使用应用层的intent实现打开网页。</p>    <p>3).监听0.0.0.0的端口转为127.0.0.1,或给相关执行动作加入用户安全提示,需用户允许才能打开网页。</p>    <p> </p>    <p> </p>    <p>来自:http://appscan.360.cn/blog/?p=165</p>    <p> </p>