议题概要
近年来,手机浏览器的安全问题一直是安全研究的焦点。大量的漏洞修补以及浏览器、操作系统层面的保护使得浏览器远程代码执行越来越难。此议题着重介绍浏览器远程执行漏洞,包括Webkit JIT漏洞,WebKit DOM漏洞,Chrome的JS引擎漏洞。漏洞相关原理,挖掘方法以及利用技巧都会涉及。
作为一种通用的漏洞缓解(Exploit Mitigation)技术,隔离堆(Isolated Heap)已经成功运用于多个主流浏览器如Chrome、FireFox、Edge、IE等。2017年下半年WebKit代码中也开始引入了隔离堆机制。WebKit中的隔离堆对于传统Exploit中的Heap Spray,UAF占位、任意地址读写等方面均造成了一定的影响。本议题中介绍了WebKit隔离堆的基本原理,它对今后WebKit漏洞发掘和利用的影响,以及360vulan团队成员在Mobile Pwn2Own比赛前针对隔离堆机制实现的Exploit预案。
作者介绍
郝力男(@holynop)在Qihoo 360 Vulcan Team从事漏洞相关研究。随团队参加pwn2own 2015/2016/2017/pwnfest 2016/mobile pwn2own 2017,参与过一些微软的赏金计划Microsoft Mitigation Bypass Bounty, Microsoft Edge Bounty, MSRC Top 100 2015/2016/2017等,曾在一些安全会议上发表文章如Blackhat/44CON/HITB等。
刘龙是360Vulcan团队的安全研究员,从事漏洞挖掘和利用方面的工作。他参加了Pwn2Own 2017和Mobile Pwn2Own 2017,并成功挑战了相关项目。他连续三年入选MSRC Top 20名单。
招啟汛是奇虎360 Vulcan Team的成员,微博ID是@老实敦厚的大宝。专注于各个主流浏览器安全和macOS/iOS系统安全,沙箱逃逸。曾参加Pwn2Own 2017和Mobile Pwn2Own 2017攻破浏览器项目。多次攻破Edge浏览器获得RCE并取得微软Edge CVE公开致谢,在MSRC 2017中排名43。多次攻破Chrome浏览器获得RCE并取得谷歌Chromium CVE公开致谢。同时多次获得苹果CVE致谢,独立发现多个Safari RCE,苹果内核本地提权等漏洞。
议题解析
在Mobile Pwn2Own 2017中我们成功pwn了两个iPhone相关的项目,分别是Apple Safari和WiFi。其中WiFi项目的要求如下:
在该项目中,我们利用iPhone连接WiFi时自动弹出的登录界面实现RCE:
该界面是通过WebCore解析渲染的,所以我们首先介绍了我们在比赛中用到的一个WebCore DOM UAF 漏洞,该漏洞POC如下:
该漏洞的成因如下图所示:
设置了form属性的button对象和form对象的关系图如上图所示,注意button的父类FormAssociatedElement包含m_form成员变量和setform函数,form的m_associatedElements成员变量中含有对button的引用。
获取了form的elements属性后,form创建了包含button引用的nodeLists成员。释放button时,button的析构函数调用setform(0),setform调用removeFormElement,removeFormElement将form的m_associatedElements成员中的button移除,但nodeLists中的button没有被移除,所以释放的button可通过form.elements访问。
要利用这个漏洞,需要先看看HTML*Element对象的结构:
一个html对象要在js层面使用,需要一个wrapper,这个wrapper的值指向WeakImpl对象。WeakImpl对象的m_jsValue指向表示这个dom对象的JSValue对象。JSValue表示一个js可操作的实体,一个JSValue可以表示很多JavaScript原始类型例如boolean, array, 甚至包括对象和函数。
Js层面执行uaf=Collections[‘id’]后的调用栈如下图:
我们具体看看WebCore::namedItems的实现。在WebCore::namedItems中可以看到如果获取到的button对象的m_wrapper非空,且满足一定的条件,其指向的m_jsValue会被作为结果返回。那么我们可以利用typedarray buffer占位,控制其中的m_wrapper值,让它最终指向一个我们伪造的Float64Array,然后通过上面的调用,在js层面获取到这个伪造的Float64Array。
由于比赛版本的Safari的ASLR实现不是很完善,我们可以利用array和typed array进行精确堆喷。堆喷后的内存布局如下图:
我们在堆喷的时候在typedarray的buffer里伪造两个结构:WeakImpl和Float64Array,其中WeakImpl中的m_jsValue值为伪造的Float64Array地址。
比赛时的safari版本还没开启隔离堆,所以我们用typed array buffer占位,所有字段都是可控的。我们将+8的位置指向spray的typedarray的buffer处,这样我们就可以通过collection[‘id’]获取到伪造的Float64Array。我们对其进行如下操作:
1.写fakedFloat64Array,然后遍历spray的typedarray,找到被修改的是哪个,后面就可以通过这个typedarray来改变我们伪造的Float64Array的pVectors值,做到任意地址读写;
2.修改pVectors值,使其指向spray的array butterfly,然后写fakedFloat64Array,用同样的方法找到被修改的array butterfly,用它来泄露任意对象地址。至此我们完成了对该漏洞的利用。
接下来我们着重讲的是JavaScript引擎的JIT编译器,事实证明,这个部分出现的漏洞的频率十分高,而且可利用性与稳定性都很好.与以往不同的是,我们在议题中不仅仅解读我们去年mp2o使用的各种浏览器漏洞,更着重于解读浏览器JIT的概念与一些机制,漏洞的挖掘过程.
首先我们介绍在Safari的JIT编译器,他的结构图如下:
我们可以看到编译器是一个十分庞大而又复杂的模块,而通过OSR机制,编译的代码可能在不同层次的优化编译器中切换.这是Safari中JIT的一种机制,可以兼并效率和安全两种特点.
下面在看看DFG的优化部分:
在议题中我们解读了一些JSC中的概念,例如structure,jsc的OSR机制,因为有OSR机制的存在,所以才避免了JIT中的一些type confusion,OOB R/W的问题.
JSC中的OSR机制的优点与缺点,还有与其他浏览器的比较。
解析完JSC中的OSR机制后,根据OSR机制的弱点,我们挖掘出的一些在mp2o上使用的漏洞:
这是漏洞的原始状态,但是在比赛前修复了,但是修复并不完全,我们发现这个修复很奇怪似乎苹果开发者并没有意识到问题的根本原因
我们在修复以后,发现了修复的绕过方法,也是我们最终在比赛使用的漏洞.在比赛前准备了很多的Safari漏洞,之所以选择这个是因为我们抽签在最后一个,所以选择了一个隐藏最深的,最不可能和别人撞洞的bug:
接下来介绍一下safari中的缓解机制 – 隔离堆:
在去年比赛中,发行版中并没有开启,但在当时的预览版已经存在了。所以为了保险起见 我们也对这个机制做了调研。这个缓解机制的引入会对我们造成怎样的影响呢?
如上所述,主要会导致一些UAF无法利用,并且全地址读写也收到影响,这里我们解释下为何使用Float64Array读写会受影响。
代码的注释说明中已经说的很清楚了,它保留了一个区域,留给索引类型的数据结构,如array/typed array,那么这个g_gigacageBasePtrs又是在哪里使用的呢?
观察Float64Array的setIndex函数,当我们要写入数据时,它会做一个重定位,重定位的基地址正是刚才的g_gigacageBasePtrs,经过几步简单的映射计算,得到在保留区域的最终目的地址,最后写入的位置也是在这个安全的位置。
它的实现我们了解了,那么绕过的方案应该从哪方面入手呢?
可以从几个大方向去考虑,我们也分别找到了对应的绕过方案,在这个会议前几天,_niklasb也公开了一种绕过方案
他的思路属于上面列举的第二种,具体实现可以参照他的利用代码
https://github.com/phoenhex/files/blob/master/exploits/ios-11.3.1/pwn_i8.js
最后我们还介绍了准备在mp2o上使用的chrome bug,这个漏洞在chrome的正式版上消失了又在比赛前重新出现,最终直接报告给了google:
会议的最后,我们放出一个彩蛋demo,就是最新版iOS 12上面通过Safari浏览器远程越狱的视频。