Group of Software Security In Progress

GoSSIP @ LoCCS.Shanghai Jiao Tong University

What Cannot Be Read, Cannot Be Leveraged? Revisiting Assumptions of JIT-ROP Defenses

Giorgi Maisuradze, Michael Backes, and Christian Rossow, Saarland University

USENIX Security’16

论文下载

概述

JIT-ROP在代码段中即时搜索可用的gadgets来绕过ASLR达成攻击。过去认为这种攻击方式依赖两点条件,代码段可读,可执行。攻击步骤分为两步,利用内存泄漏漏洞和脚本执行环境来寻找可以的使用的gadgets,利用控制流漏洞执行gadgets。而XNR被认为是对JIT-ROP攻击的一种完备的防御手段.

作者发现通过在可以在可预测的位置利用即时编译产生的代码的位置偏移构造特殊的连续字节。从而产生可以使用的gadgets.

先前的研究表明,通过在代码段中插入一些赋值代码,可以在编译产生的汇编代码中构造出任意的gadgets,现代浏览器因此对所有常量进行了混淆。但我们发现,通过对跳转指令的构造,我们也可以在代码段中编码特定的值,因而对代码段的读并不是攻击的必要条件。现行细粒度的代码随机化和XNR机制并不能防御新的攻击。

新的攻击方法

预设条件

开启了DEP,ASLR,None-readable codes,所有非JIT生成的代码指针都是匿名的, randomized JIT pages, constant blinding,和 guard pages。同时攻击者拥有一个内存泄漏漏洞,改变控制流漏洞,和Javascript环境。

利用条件跳转指令构造gadgets

我们可以利用JS中的if/else for/while构造特殊的连续字节,下面的图是一个很好的例子。

Fig

解释器生成的汇编代码中包含一个偏移地址0XC380CD,在小端模式下下正好是int 0x80;ret;的16进制值。利用这种方式,我们可以在程序中构造合适的gadgets。在这里我们需要知道我们构造的JIT函数的位置,这可以通过将这个函数指针传给另一个JIT函数,然后在另一个JIT函数中读取栈上的值来获取。(此处假设栈地址已知)

作者在Chrome 33 (32-bit)/Chrome 51(64-bit), Firefox 42 (64-bit) and IE 11 (64-bit with 32-bit JavaScript engine)进行了实践。生成0XC380CD,在Chrome上利用了

S1: v=v1+v2,     0x10 bytes
S2: v=0x01010101  0xd bytes

通过使用S1,0xc380c次,S2,1次构造除了期望的gadget。这里有一点值得注意的是对齐,可以在跳转指令前面加入一个奇数长的指令来构造任意的字节。

在Chrome 64和Firefox上,同样可以使用一些其他指令达成功能。IE浏览器有一些特殊,他限制JIT生成代码段长度,并且会随机插入一些NOP指令。但我们依旧可以控制起码两个高位的字节。

利用直接调用构造gadgets

在直接调用中的常数编码了一个指令到函数的相对偏移,我们可以利用这个常数构造一个3字节长度的gadget。

Fig

可以构造类似上面这样的函数,asm_call是一个占位符,同样作为例子,我们希望生成一个0xc3结尾的gadget,此时希望知道被调用函数(一个JIT内部函数,例如V8的helper函数)的位置。虽然他们的位置被随机化了,但是对应的JS结构体中却保存了指针,可以利用内存泄漏漏洞获得他们的值。

在这里,我们需要申请一个16MB申请了的内存存放我们的函数,在其中填满我们的占位符。 可以发现常数偏移会有这样的形式0xY ***,Y由于对齐是一个非任意值。同样,我们可以在call指令前面加入奇数长的指令来改变Y。 同样,作者在Chrome 33 (32-bit)/Chrome 51(64-bit), Firefox 42 (64-bit) and IE 11 (64-bit with 32-bit JavaScript engine)进行了实践.

在Chrome上没有任何特殊的地方,而在firefox上,因为没有直接调用,这种构造方法无法实现。在IE 上,每个函数最长1MB,攻击时需要一些技巧,作者在IE上申请了0x80个这样的函数,每个函数内最高位置1个字节都只有两种取值。在找到一个合适的函数后,将位置的占位函数释放,留给JIT编译生成的函数。最后,我们可以在栈上用下图的函数读取cookie,验证偏移是否正确。

Fig

Fig

最后作者结合两种方法生成了类似下面的gadgets

Fig

生成过程在Chrome 上用了1.3s, in a VirtualBox Virtual Machine running Windows 10 (Intel Core i5-4690 CPU 3.50GHz).

防御

作者总结了这三个浏览器上的防御措施和安全缺陷,如下面两张图。

Fig

Fig

并对应的提出两个防御措施。将所有直接调用转化为间接调用,并且对使用的偏移进行混淆。

Fig

将所有的间接跳转转化为直接跳转。

Fig

性能评价

作者在V8上进行了修改,用V8 Benchmark Suite7作为标准测试,平均时间额外开销在2%,原来生成代码大小为1123KB,修改后为1411KB,额外空间占用为26%。

作为附加,还测试了两个带有超过100万个跳转的函数“ifs true”,“ifs false”,每个函数调用10次 14,25% overhead in “ifs false” and,9,81% for “ifs true”.

结论

作者提出了针对现有JIT-ROP defenses 的两种攻击方法,利用间接跳转和直接调用构造特殊的连续字节作为gadget,并对应给出了自己的解决办法,在V8上进行了实现。获得了很低的overhead