前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Gadget构造:从JIT-ROP到对抗XnR

Gadget构造:从JIT-ROP到对抗XnR

作者头像
FB客服
发布2018-02-28 16:16:10
1.7K0
发布2018-02-28 16:16:10
举报
文章被收录于专栏:FreeBufFreeBuf

写在前面

简单地说,本文介绍了两种构造gadget的思路。(在浏览器支持JIT的情况下)

演进:关于JIT-ROP

我们知道,最初DEP的出现是为了对抗的栈溢出、堆溢出等这类劫持程序执行流的攻击手法。在这之后,攻击者为了绕过DEP,开始利用libc.so中的函数获取shell,也就是我们所说的Ret2libc攻击。更有效的防御手段还有ASLR地址随机化,使得libc.so加载的基址每次都会发生变化。当然,如果存在地址泄露等,ASLR仍可以被绕过。

于是乎,学术界前几年开始研究细粒度的ASLR,即使基址被泄露,攻击者也得不到准确的地址。

2013年s&p上发表了一篇文章提出JIT-ROP,这项工作极具创新性。其意义在于它提出了在运行时寻找gadget同时构造ROP链的概念。详细的过程是这样的:在存在一个内存泄露漏洞的情况下,得到一个运行时代码指针,它泄露当前4k内存页,因为当前页可能会有分支指向其他页,所以通过这个指针可以得到尽可能多的页。将当前页运行时反汇编后,获得所需要的gadget并构造ROP链。

也就是说,JIT-ROP是通过即时扫描有效内存,即时反汇编搜寻rop gadgets,即时拼接shellcode,从而绕过dep/aslr的,它在程序运行过程中动态执行,所依赖的资源在进程地址空间中获取。所以它和传统rop最大的不同在于:它可以使用任何代码指针初始化攻击环境,而传统的rop需要泄露函数的具体地址。

这种攻击手段可以绕过学术界过去提出的任意粒度的ASLR。

演进:关于XnR

为了针对JIT-ROP,14年ccs有一篇文章提出了XnR,利用软件模拟的方式实现了页的不可读。

既然页不可读,那么JIT-ROP所提出的运行时读内存页然后搜寻可用gadget这一思想就行不通了。

那么如何对抗不可读,提出使JIT-ROP攻击不需要“可读”这一条件,也可达成呢?这就是下面要讨论的内容了。

相关:关于JIT

在进入正题之前,先简单说说JIT引擎是什么。

2008年,浏览器的JavaScript引擎引入JIT技术。JIT是一种即时编译技术,是一种解决浏览器效率低下的方案。例如Javascript,它是典型的解释型语言。程序员写了一个for循环,解释器是不知道这是一个循环的,所以它将会一句一句的去循环执行这个循环。这也是为什么解释型语言的效率特别低,因为它不会预先编译。

JIT引擎的出现就是为了改善这一情况。它通过在运行时将部分语句编译为机器码,于是下次执行不需要再翻译,从而省去了解释开销,使得浏览器性能大幅度改善。

JIT与攻击

早期利用JIT新特性进行攻击的方案是在2010年blackhat大会上提出的Pointer Inference and JIT Spraying,将 ActionScript代码中进行大量的XOR操作。然后编译成字节码,并且多次更新到Flash VM中,这样它会建立很多带有恶意Xor操作的内存块。

但一方面这样的方法比较旧,另一方面,学术界中早已提出防御方法JITDefender。

准备工作

攻击模型

(1)存在内存泄露漏洞 (2)不考虑CFI (3)JavaScript环境

之所以如此,因为这篇文章的中心思想是,攻击者可以通过自己注入gadget实现绕过其他限制手段如XnR。关注点并非实现真实过程的控制流转移。

防御环境

(1)DEP:NX,可写不可执行 (2)ASLR: fine-grained,XnR应用于可执行文件,库,JIT编译而成的代码 (3)Non-Readable Code: 所有代码段不可读 (4)Hidden Code Pointers: 除了JIT-compiled的指针均已匿名 (5)JIT Hardening: JIT上的防御手段,比如randomized JIT pages, constant blinding,guard pages

攻击方法

方法一:利用条件跳转语句

原理:构造if/else,for/while,编译成包含可预知的条件跳转指令。

举例说明一下,如果我们需要的gadget是int 0x80;ret ,翻译成机器码也就是0xcd80c3

那么,则往if中写入0xc380cd字节大小的JS代码。

如上右图,攻击者是可以确定,编译结果中肯定包含‘je 0xc380cd’这一句的(x86/x64 架构采用小端存储)。所以说,通过变化if中js代码的大小,我们可以修改代码长度,改变跳转的距离。而每句JS代码编译后的大小是已知固定的。所以攻击者可以精确的控制所生成的代码长度。即,je后面的值,可以随意控制。

举个更具体的例子,在Chrome 33 (32-bit)/Chrome 51(64-bit)上,如果需要一个gadget:0xcd80c3。

S1: v=v1+v2, compiling to 0x10 bytes(64位 v=v)

S2: v=0x01010101, compiling to 0xd bytes.

使用S1 0c380c次(得到结果0xc380c0),

再使用S2 一次,求和即得到0xc380cd。

以上步骤可以注入自己想要的gadget,接下来就是要找到gadget所在的位置。

(1)首先通过内存泄露漏洞,得到JIT所编译的JavaScript代码的函数地址

(2)将这个函数的作为参数传给另一个函数,这样它就被push到stack中了(javascript的特性)。

(3)得到栈的信息,得到函数对象的指针,它包含了指向实际地址的指针。

方法二:利用直接调用语句

上一种方法对IE基本是无效的。IE部署了JIT-hardening策略,会随机插入NOP,改变条件跳转语句的值。这样,编译后的语句就不可控了。于是作者又提出使用直接调用指令实现攻击。如:call 0x1234560

原理:任何两个直接调用指令即时调用同一个函数,机器码是不一样的。其实和条件跳转的原理差不多。之前控制的是je指令后边的值,那它控制的是什么呢。其实利用的是call后面的这个值是一个相对地址,第一次调用产生的机器码是被调用者和下一次所调用的差。如下图。

假设FUN函数在2000的位置。那么在图中,连续CALL FUN_1,所以这个常数代表FUN1和第二条CALL FUN1(即0x5)的距离。即0x2000-0x5=0x1ffb。(0x5是一条call指令的大小)。这个例子里,攻击者得到的是0xe8fb1f0000。

嗯,以上是大概思路。具体攻击流程有三步:

(1)找到call指令后那个被调用函数的地址。

再列一遍这个式子,0x2000-0x5=0x1ffb。在这里0x2000就是被调用函数的地址。

总之,一般来说,在javascript环境下,可以利用当然是地址已知的helper函数或built-in函数(比如Math.random,String.substring)。

另外不得不说到IE,它的built-in函数在library中,而且采用了细粒度的ASLR。但是它们所产生的JS对象,未启用随机化,而且包含指向这个函数的指针。所以对于IE也是可行的。

(2)把call指令放到指定位置。

再列一遍这个式子,0x2000-0x5=0x1ffb

还是假设我们需要的gadget是int 0x80;ret (即0xcd80c3)。

0xcd80c3,包含三个字节。也就是说,上面那个减法式子的结果必须保证位数满足要求,要是你的距离才两位是怎么也构造不出三位的gadget的。于是为保证三字节距离,需要创建一个由直接调用语句组成的JS函数,使它在编译后覆盖0x100 00 00字节。即我们要求第一次和最后一次CALL之间的距离,至少为0x1 00 00 00字节指令。

(3)检查机制

还是要说到IE,它在编译时会随机插入NOP,所以基本上不能知道函数会被编译到哪个地址。而且,前提条件存在XnR,我们是不可以通过读取代码段来确定那个位置是否是所需要的gadget的。

那么,只能通过取得足够大小的代码空间,全部填满call指令,从而确保计算结果在距离范围内。

Javascript中的check address函数会读栈中数据,直到找到call指令放置的ret,可知是否放置正确。如果没有,重新编译,重复之前的步骤。

其他

这攻击主要针对的是x86 (32- or 64-bit)架构。在RISC架构中,如ARM,MIPS,由于硬件层次的原因,利用上文所述的方法不能成功攻击。除非在ARM架构下,攻击者强制切换为16-bit THUMB模式。

另外,虽然论文中作者是以浏览器为例,但其实采用jit引擎的东西应该都适用(?)。比如pdf阅读器是可以的。

总结

实际上本文的核心思想很简单:

(1)攻击者通过构造JS代码产生一个jit-compile gadget

(2)由于所产生的gadget是攻击者控制的,所以不需要搜索,不需要读页,即可被攻击者用来构造ROP链

(3)以上过程发生在运行时

参考文献

[1] What Cannot Be Read, Cannot Be Leveraged? Revisiting Assumptions of JIT-ROP Defenses. USENIX 2016

[2] Just-In-Time Code Reuse: On the Effectiveness of Fine-Grained Address Space Layout Randomization. IEEE S&P 2013

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-07-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeBuf 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 演进:关于JIT-ROP
  • 演进:关于XnR
  • 相关:关于JIT
    • JIT与攻击
    • 准备工作
      • 攻击模型
        • 防御环境
        • 攻击方法
          • 方法一:利用条件跳转语句
            • 方法二:利用直接调用语句
            • 其他
            • 总结
            • 参考文献
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档