对MS16-063漏洞补丁的分析

几周前微软又发布了MS16-063的每月计划更新。本次更新对象为 IE ,修复了 jscript9.dll中的 TypedArrayDataView两个函数。

补丁前后改动分析

同样的,本次也是用 BinDiff来分析5月和6月的 jscript9.dll的区别:

bindiff_diff

上次不同,这次的改动就非常多了。但是如果仔细看下,大部分的改动都是和 DirectGetItemDirectSetItem方法和 TypedArray及其关联类有关。同时也能看到 DataView类里的 GetValueSetValue的函数的改动。

bindiff_diff_2

TypedArrayDataView

有关 TypedArray更多资料,可以阅读这里,但是它提供了的那个用于访问的函数是受一个 ArrayBuffer备份原始二进制数据的机制。

ArrayBuffer是不能被直接访问与操作的,只能通过 view这类高级接口来操作,它会提供一段包含自身类型,偏移,多个元素的内容。

DataView,我们可以得到灵活的读取和写入任意的字节顺序(字节序)任意数据项。

TypedArray,我们可以指定数组元素的数据类型为以下之一:

  • Int8Array: 有符号 8-bit 整数
  • Uint8Array: 无符号 8-bit 整数
  • Uint8ClampedArray: 无符号 8-bit 插值整数 (插值基于 0 到 255)
  • Int16Array: 有符号 16-bit 整数
  • Uint16Array: 无符号 16-bit 整数
  • Int32Array: 有符号 32-bit 整数
  • Uint32Array: 无符号 32-bit 整数
  • Float32Array: 32-bit IEEE 浮点数 (float)
  • Float64Array: 64-bit IEEE 浮点数 (double)

 

TypedArrayDataView两个函数在访问与操作原始数据的功能上相似,接下来看看更新的内容。

分析

下图中很清楚的看到更新后的版本添加了一些代码:(左6月右5月)

bindiff_func

更新前, DirectGetItemDirectSetItem每个类型数组只是检查索引是不是超出了范围,然后读入缓冲区。

getdirectitem_may

伪代码大致如下:

请注意,这里的缓冲区根本就没有检查自身数据,因此缓冲区可以在被访问或操作前分离,从而产生UAF漏洞。

这时候可以强制一下 ArrayBuffer通过使用 postMessage传值来分离缓冲区,下面的代码段足以脱离由 AB引用的 ArrayBuffer

修改后的代码会自己检查缓冲区逃逸问题,从而防止UAF发生。

getdirectitem_june

有趣的是,这个漏洞明明已经在ChakraCore16年1月的首次提交里已经修复了....不知道这次漏洞再次产生是什么鬼......

本次最终更新之后, jscript9也会去验证一遍 TypedArrayDataView两个函数的缓冲区逃逸,确保UAF不发生。

触发PoC

触发来说就简单很多了:

  1. 创建一个 TypedArray——我们可以用任何类型的数据,但是这里使用 Int8Array
  2. 通过第一步的 Int8Array制造一个 ArrayBuffer的缓冲区逃逸,用来释放缓冲区
  3. 使用 Int8Array访问已经被释放的缓冲区
成功crash:

poc_crash

总的来说,这个PoC在写入已经被释放的内存(即ia[100]现在指向空闲内存)从而导致程序崩溃。对攻击来说,则需要创建并且先分配这个对象的元数据,这样才会有任意内存读写的效果。

Exploit

测试环境为Windows7,IE11,以及edge,因为目前这些版本还没有修复该漏洞。

根据上文PoC说到的,首先要分配一个 ArrayBuffer对象,使用 Int8Array,然后继续分配一个较大的 ArrayBuffer缓冲区(大致2MB),这样内存就会在使用后被系统释放。使用这种方法的好处是不需要对缓冲区大小做太严格的限制,大致2MB就可以了。

一旦触发了内存回收机制,就可以填充N多较小的数据到那个被释放的内存空间里,达到内容可控的效果。

以上的操作会触发LFH控制大小的类函数 sizeof(Uint8Array),同时多个内存块也会被LFH分配。

可以用VMMap来查看一下:

vmmap_0 vmmap_1 vmmap_2 vmmap_3

现在就要定位一个我们刚刚创建过的 Uint8Array的对象, Uint8Array类有4byte长,这时候需要搜索下刚刚定义的ab2(0x1337),找到之后就需要手动增加对应数组 arr的长度。

现在这个刚刚分配的特殊的 Uint8Array对象将用来作为读取存储view和写入任意内存的变量:

和上次一样,我们编写简单的辅助功能:

接下来,根据目标环境的不同,我们也有很多不同的方法来实现上面的攻击,对于开始提到的Win7IE11环境,攻击方案如下:

  1. 计算泄露vftable地址的jscript9基址
  2. 在堆缓冲区建立一个fake virtual function table
      使用stack-pivot gadget替换子数组的指针
      mov esp, ebx; pop ebx; ret
      注意:EBX是我们提供给子数组的第一个参数
  3. 读取 VirtualProtect入口,导入表
  4. 构造ROP Payload,调用函数 VirtualProtect到shellcode的缓冲区
  5. 覆盖原来 Uint8Array对象 的vftable地址为我们刚刚构造的那个
  6. 调用mv.subarray,完成

shellcode成功的启动了notepad:

poc_notepad

不过这个记事本是运行在沙箱+低权限环境的,提权不在本文的讨论范围之内。

Exp已经上传到众多程序猿基佬都喜欢用的Gayhub

以上。

(本文已授权爱安全使用)

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

回复 (0)

› 尚无评论。

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

允许使用的标签 - 您可以在评论中使用如下的 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  :(  :!:  :?:

引用通告 (0)

› 尚无引用通告。

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