对CVE-2016-0189漏洞补丁的分析

上个月,微软发布了 MS16-051 安全漏洞更新。此次安全更新修复了一个 IE 游览器的脚本引擎漏洞 (CVE-2016-0189)

已修复与未修复对比

对于 dll文件,可以使用 BinDiff来对比修复和未修复的版本。本次对比的目标是 vbscript.dll文件

这次补丁只修改了几个函数而已,修改如下

bindiff

其中改动最为可疑的就是 AccessArray函数,用 IDA 反一下这个函数:

access_array_april access_array_may

上图为4月与5月,也就是修改前与修改后的对比,下文同样图也为对比,不再赘述

很清楚就能看到区别了,更新的内容是在代码访问之前给数组设置了一个 lock 。

接下来看一眼 IsUnsafeAllowed里有关安全的策略:

is_unsafe_allowed_april

is_unsafe_allowed_may

嘛,同样的,这里的修改也很明显了,在更新前, IsUnsafeAllowed调用一个在不测试安全策略情况下永远都会返回0的一个函数。更新后,这个函数会调用位于 QueryProtectedPolicyPtr函数指针。现在,函数 InitializeProtectedPolicy会使用 GetProcAddress初始化函数指针。

initialize_protected_policy

分析

本次更新修复了两个已知的漏洞,现在可以根据这两个修复来编写相应的利用代码。

漏洞1 AccessArray中缺失的 SafeArray lock

鉴于更新在数组中所插入的代码,攻击者可以在访问数组的过程中通过某些手段修改数组,导致部分属性的定义(如 cDimscbElements会出现不匹配的错误。

主循环中,该代码从数组最右侧开始计算给定的索引数据指针。需要注意的是,如果被用于索引的变量类型是 VT_I2或者 VT_I4的时候读值方式会略有不同,分别读取 longshort。对于其他变量类型, rtVariantChangeTypeEx将会调用索引值。当这个函数被给定一个 Javascript对象时,它将会通过所以来找到最终调用对象的 valueOf的值。通过提供具有我们所选择的 valueOf函数的对象,我们可以运行任意 VBScriptrtVariantChangeTypeEx内的 Javascript代码。

我们可以通过以上触发脚本来重新定义数组长度。一个栗子,想象一下我们用一个二维数组

然后,当我们用类似 A(1, 2)访问这个数组的时候, AccessArray中的 idx就会计算成1 + (2 * (2 - 0)),结果为5。

一般来说这并不会造成什么问题,因为缓冲区里定位的数据是16×2×2001=64032位,然而,这种偏移量将会导致溢出内容被重新定义为较小的一段数据。总而言之,我们可以在当数组定义为 A(1, 1)的时候访问到 A(1, 2)的数据。

通过重复触发这个漏洞,我们很轻松的就可以把我们的攻击代码写入到数组里。得到对象的地址,读取某个地址的内存数据,甚至可以通过重复触发漏洞来复写这部分的数据。

漏洞2 绕过 IsUnsafeAllowed

在更新之前, IsUnsafeAllowed函数是一直在返回1的。因为 COleScript::OnEnterBreakPoint 傻到一直在返回0。更新之后,程序就会正确的执行 QueryProtectedPolicy函数(Windows8.1以上系统)。

使用 SafeMode绕过

一般情况下,IE会自动阻止一些危险脚本的运行。在safemode的那个flag为0xE的时候会自己用 InSafeMode去检测一遍。幸运的是,我们知道 IsUnsafeAllowed会一直返回1,所以我们就可以通过修改这个flage的值来达到攻击漏洞1的目的。

in_safe_mode

但是这并没有跳出IE的沙箱环境。下面的exp将告诉你如何跳出这个沙箱环境。

触发PoC

下面的代码是让本来能访问到的内存空间无效化才能让IE崩溃的。第二个数组的大小在函数访问数组的过程中被改为了较小的值。

vbscript_crash_poc

Exploit

任意读写基元的危害是很大的,为了让exp代码好看一点,我稍微改了一下。

  • getAddr触发对象地址的喷射,这样找内存地址就方便很多了
  • leakMem触发这个bug,顺便读取一下给定地址的内存
  • overwrite触发bug,同时复写指定地址的内容,方法是通过先修改 CSng(0)变量,比如想要开Godmode,只需要把flag改成0x04

有了这些,就可以做下面的一些事

  1. 实例化一些VB脚本类
  2. 获取类对象的地址
  3. 通过类实例的地址获取 CSession的泄漏点地址
  4. 通过获取 CSession地址来得到 COleScript的地址
  5. 复写 COleScriptSafetyOption

最终exp代码如下:(已于Win10,IE11测试通过)

效果如图:

notepad_screenshot

续写一些内容

有小伙伴问我为啥不向别人一样弹个calc出来........

即使绕过了SafeMode,沙箱的保护模式也会过滤IE进程的一些执行函数的,比如WinExec和CreateProcess

在注册表的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Low Rights\ElevationPolicy里,有很多注册的键里都是和安全策略有关的,这些策略保护着沙箱模式的安全问题。关于更多沙箱模式的策略介绍可以看这里,重要的是列表定义的环境里没法指定特殊程序的运行,这意味着IE就会应用默认的策略,后果就是运行某个特定程序的时候就会弹窗了。

notepad_cmd elevation_policy

上面很清楚的写了,notepad的策略值为3,而cmd的策略值为0,是无法启动的。

而且,从windows8.1开始,计算器这个工具已经运行在了AppContainer里。不过我们还是可以运行一些没有定义安全策略的软件,比如wordpad(写字板),只是也是会弹窗罢了。

wordpad_prompt

只有点了Allow,IE才能在子进程里运行Wordpad

wordpad_medium

那,有没有办法绕过这个弹窗提示,直接执行这个程序呢?

办法是有的

几年前,zerodayinitiative组织就向微软上报了一个bug,不过看样子微软并没有重视这个0day,所以我还是可以简单利用一下这个漏洞的。

原理是中权值等级程序的子进程在沙箱环境里可以执行任意代码的这个bug。具体内容已经在ZDI的这个文章里写的很详细了,我就不搬过来了,有兴趣的同学可以看一下。但是主要思想就还是使用IE对内联网的localhost信任,在本地创建一个服务器,然后让IE以低进程权值去访问这个服务,从而达到代码执行的目的。

这里搬运一下ZDI博客的那个图,会让你了解的更详细直观一些:

zdi_blog_image

利用文章里给出的部分PoC就可以完成跳出沙箱的操作了。

具体的exp我发到了gayhub里,来一发效果图:

cmd_screenshot

以上

P.S.由于一些特殊原因,如果十分必要,可以向我发送PGP签名信息。参见about me

声明: 本文采用 BY-NC-SA 协议进行授权 | Deamwork
转载请注明转自《对CVE-2016-0189漏洞补丁的分析
本文地址:https://www.deamwork.com/archives/patch-analysis-of-cve-2016-0189.orz6

回复 (1)

  1. hk China Google Chrome Windows   / 回复

    楼主,文章中分析过程中出现的一些函数,比如VAR::PvarCutAll这样的函数它的作用和相关的一些参数是怎么了解的?

发表评论 修改评论取消编辑

允许使用的标签 - 您可以在评论中使用如下的 HTML 标签以及属性。

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <img src="" alt=""> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

 :mrgreen:  :|  :twisted:  :arrow:  8O  :)  :?  8-)  :evil:  :D  :idea:  :oops:  :P  :roll:  ;)  :cry:  :o  :lol:  :x  :(  :!:  :?:

引用通告 (1)

欢迎来到Deamwork! o(∩_∩)o
X