探索黑客技术攻防,实战研究与安全创新

导航菜单

对 IE的 MS16-063 漏洞补丁分析

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

补丁前后改动分析:

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

图片6.png

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

图片7.png

TypedArray 和  DataView:

有关  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)

TypedArray 和  DataView 两个函数在访问与操作原始数据的功能上相似,接下来看看更新的内容。    分析下图中很清楚的看到更新后的版本添加了一些代码:(左 6 月右 5 月)

图片8.png

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

图片9.png

伪代码大致如下:

QQ截图20160907094710.png

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

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

QQ截图20160907094735.png

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

图片10.png

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

QQ截图20160907094817.png

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

触发来说就简单很多了:

1.创建一个  TypedArray——我们可以用任何类型的数据,但是这里使用  Int8Array

2.通过第一步的  Int8Array 制造一个  ArrayBuffer 的缓冲区逃逸,用来释放缓冲区

3.使用  Int8Array 访问已经被释放的缓冲区


QQ截图20160907094830.png

成功 crash:

QQ截图20160907094920.png

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

Exploit:

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

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

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

QQ截图20160907095008.png

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

可以用 VMMap  来查看一下:

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

QQ截图20160907095106.png

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

QQ截图20160907095331.png

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

QQ截图20160907095240.png

接下来,根据目标环境的不同,我们也有很多不同的方法来实现上面的攻击,对于开始提到的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:图片13.png

不过这个记事本是运行在沙箱+低权限环境的,提权不在本文的讨论范围之内。    Exp 已经上传到众多程序猿都喜欢用的 Gayhub。

本文为网络安全技术研究记录,文中技术研究环境为本地搭建或经过目标主体授权测试研究,内容已去除关键敏感信息和代码,以防止被恶意利用。文章内提及的漏洞均已修复,在挖掘、提交相关漏洞的过程中,应严格遵守相关法律法规。

相关推荐