从BinDiff到0day:IE浏览器UAF漏洞分析

阅读量    145901 |   稿费 160

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

0x00 前言

去年6月份,我向微软报告了IE浏览器中的一个UAF(释放后重用)漏洞,漏洞被官方定位严重级别,编号为CVE-2019-1208,微软在9月份的周二补丁日修复了这个漏洞。我通过BinDiff(一款二进制代码分析工具)发现了这个缺陷,编写了一个PoC来演示如何在Windows 10 RS5系统中利用该漏洞。

本文简要介绍了这个漏洞研究过程,如果想深入分析该漏洞,大家可参考这篇技术简报

 

0x01 CVE-2019-1208

前面提到过,CVE-2019-1208是一个UAF漏洞。这类安全问题会破坏数据有效性、导致进程崩溃,并且攻击者可以根据漏洞触发方式来执行任意代码或者远程代码。一旦成功利用CVE-2019-1208漏洞,攻击者就可以获得系统中与当前用户的相同权限。如果当前用户具备管理员权限,那么攻击者就可以劫持受影响的系统,比如安装或者卸载程序、查看并修改数据来创建具备完整权限的用户账户等。

 

0x02 潜在影响

在比较直观的攻击场景中,攻击者可以通过社会工程学方式向未知用户发送钓鱼邮件,诱导用户通过IE浏览器访问(包含CVE-2019-1208利用代码的)恶意站点即可。此外,攻击者也可以发送垃圾邮件,附件中包含该漏洞的利用代码。这些附件可以是启用了IE渲染引擎的微软Office文档,或者包含ActiveX控件的应用程序文件,然后在控件中包含漏洞利用代码。攻击者同样可以攻破与用户有数据交互(比如广告数据)的合法网站后,在上面托管利用代码。

图1. VbsJoin代码执行流

 

0x03 发现过程

故事源自于BinDiff,当时我想比较下微软在5月份和6月份的vbscript.dll中函数做了哪些改动(vbscript.dll是包含VBScript引擎相关API函数的一个模块)。我发现微软在SafeArrayAddRefSafeArrayReleaseData以及SafeArrayReleaseDescriptor这几个函数上做了改动。

进一步研究后,在之前自己发现的另一个漏洞(CVE-2018-8373)的启发下,我通过如下步骤,使用VBScriptClass触发了一个UAF问题:

1、arr = Array(New MyClass):创建一个SafeArray,将VBScriptclass: MyClass保存在arr[0]中;

2、Callback: arr = Array(0)Join(arr)会触发MyClassPublic Default Property Get回调函数。这个回调中会为变量arr创建一个新的SafeArray。如图1所示,新的SafeArray并没有受SafeArrayAddRef函数保护。因此,浏览器正常设想的代码流会被这个回调函数打破;

3、arr(0) = Join(arr):当从Public Default Property Get回调函数返回后,VbsJoin的代码执行流将调用SafeArrayReleaseData以及SafeArrayReleaseDescriptor来减少SafeArrayData以及SafeArrayDescriptor的引用计数。然而,新的SafeArray不受SafeArrayAddRef保护,且SafeArrayData以及SafeArrayDescriptor的引用计数为0。因此,新的SafeArraySafeArrayData以及SafeArrayDescriptor会在SafeArrayReleaseData以及SafeArrayReleaseDescriptor函数中释放,如图2所示。

图2. 内存布局,从上到下分别为arr = Array(New MyClass)arr = Array(0)以及回调函数(红色高亮框)

当浏览器将VbsJoin的返回值保存到arr(0)中时,PoC会在vbscript!AccessArray中崩溃(如图3所示),因为SafeArrayDescriptor已经被释放,但arr变量依然保存着指向已被释放的SafeArrayDescriptor的指针。

图3. PoC在vbscript!AccessArray中崩溃

 

0x04 触发UAF

PoC是否成功触发了UAF?从某种程度上来看,答案是肯定的。为了演示如何完全触发UAF,我使用基本的BSTR字符串(基本字符串/二进制字符串)作为数据结构。SafeArray是一个多维数组,但由于VbsJoin只能处理单维数组,我在回调函数中修改了SafeArray的维度。不幸的是,这种方法无法奏效,会抛出一个运行时错误,表示数组类型与Join中的类型不匹配。我使用了On Error Resume Next来绕过这个运行时错误。修改版的PoC如图4所示。

图4. 使用On Error Resume Next的修改版PoC

获取0x20字节的被释放内存后,我使用了大小为0x20字节的BSTR来伪造一个较大的SafeArray。通过堆风水技术,这个BSTR可以稳定重用0x20字节被释放的内存。如图5上半图所示,最终我得到了一个伪造的一维SafeArray,该数组元素个数为0x7ffffffff,每个元素大小为1字节:

图5. 伪造的SafeArray(上)以及用于读/写的地址(下)

我成功伪造了一个SafeArray,可以用来读写从0x000000000x7fffffff的内存空间。为了泄露一些读/写地址,便于漏洞利用,我借鉴了Zuckerbraun之前的研究成果,使用堆喷射来获取一些固定的读/写地址(0x28281000,如图5下所示)。

 

0x05 利用UAF实现RCE

按照Simon Zuckerbraun文章中的思路,我使用Scripting.Dictionary对象来实现RCE(远程代码执行),但使用另一种方法来构造虚假的Dictionary。这一次我使用的是BSTR,采用如下步骤,如图6所示。

1、使用读/写内存函数来读取原始的Dictionary内存,将对应的数据保存到一个BSTR中,然后将VBADictionary::Exists替换为kernel32!Winexec

2、将Winexec参数(\..\calc.exe)写入这个BSTR;

3、将这个BSTR保存到util_memory + 0x1000,然后修改util_memory + 0x1000 – 8 = 9,使得fake_array(util_memory + 0x1000)能被识别成一个对象;

4、利用fake_array(util_memory + &h1000).Exists来触发Winexec函数。

图6. 伪造的Dictionary内存布局

图10. 成功实现RCE

 

0x06 总结

之前Windows 10中已经禁用了VBScript,在2019年8月13日,微软又在Windows 7、8以及8.1的IE浏览器中禁用了VBScript,因此我们只在本地模式验证了这个PoC。然而微软也提到过,用户可以通过注册表或者组策略重新启用这个设置。与此同时,用户以及公司应当始终采用最佳的防御策略:保持系统及时更新并打上补丁、禁用不需使用的(或者需要限制使用的)组件、在网络安全上警惕攻击者可能使用的攻击媒介(比如垃圾邮件或者其他社会工程学威胁等)。

完整的研究细节可参考这篇技术简报

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多