Readactor: Practical Code Randomization Resilient to Memory Disclosure阅读笔记(一)

来源:互联网 发布:win7启用网络发现 编辑:程序博客网 时间:2024/06/17 06:24

Readactor:代码随机化应对内存泄漏问题-阅读笔记(一)

前段时间在学习信息系统安全方面的内容,阅读了很多相关论文。其中对Readactor: Practical Code Randomization Resilient to Memory Disclosure这篇论文阅读之后,我进行了一些整理和总结,讨论了我对这篇论文的理解、分析和评价,论文工作的核心思想和主要贡献,其中包括论文所针对的问题和所实现的目标,供有需要的人参考。这篇论文刚开始读的时候我感觉不是很好理解,它涉及到了软件代码安全和硬件保护等方面的知识,而且顶级会议S&P上的文献,果然也是很难懂的。好了,下面我们就开始吧。

报告目录

  • 要解决什么问题
  • 相关背景知识
  • 该领域研究现状
  • 本论文实现目标
  • 论文核心思想
  • 论文主要贡献
  • 本文具体工作内容分析
  • 论文中的攻击模型和假设
  • 实验结果评价
  • 结论

要解决什么问题

本文提出的方法主要是针对解决代码重用攻击(Code-reuse attacks),比如ROP攻击。这些攻击严重威胁了现代软件的安全,因此急需设计一种实用且有效的防御方式来抵抗代码重用攻击。然而之前提出的所有方法都存在问题,有的方法存在内存泄漏漏洞,有的方法在实际商业系统的部署中无法实施。因此本文要解决的问题就是既能防止代码重用攻击,又能避免其他方法存在的内存泄漏和无法实际操作使用的问题。

相关背景知识

本文提到了许多重要的概念和名词,掌握它们以及相关背景知识有助于理解整篇文章。

1、ROP(Return-oriented Programming)

返回导向编程技术。核心思想是在整个进程空间内现存的函数中寻找适合指令片断(gadget),并通过精心设计返回堆栈把各个gadget拼接起来,从而达到恶意攻击的目的。构造ROP攻击的难点在于,我们需要在整个进程空间中搜索我们需要的gadgets,这需要花费相当长的时间。但一旦完成了“搜索”和“拼接”,这样的攻击是无法抵挡的,因为它用到的都是内存中合法的的代码,普通的杀毒引擎对ROP攻击是无计可施的。

2、DEP(Data Execution Prevention)

数据执行保护。DEP是一套软硬件技术,能够在内存上执行额外检查以帮助防止在系统上运行恶意代码。可帮助防止数据页当作代码执行,从而有效分离数据与代码。通常情况下,不执行默认堆和堆栈中的代码。硬件实施 DEP 检测从这些位置运行的代码,并在发现执行情况时引发异常。软件实施 DEP 可帮助阻止恶意代码利用 Windows 中的异常处理机制进行破坏。

3、ASLR(Address Space Layout Randomization)

地址空间格局随机化。是为了应对Return-in-to libc攻击的技术。在Return-in-to libc攻击方式中,我最为关键的一点是攻击者事先预知了特定函数,如system或VirtualProtect的入口地址。在Windows XP或Windows 2000上,这些函数的入口地址是固定的,即攻击者事先可以确定的。因此ASLR的原理就是在当一个应用程序或动态链接库,如kernel32.dll,被加载时,如果其选择了被ASLR保护,那么系统就会将其加载的基址随机设定。这样,攻击者就无法事先预知动态库,如kernel32.dll的基址,也就无法事先确定特定函数,如VirtualProtect,的入口地址了。

4、Code randomization[40]

代码随机化。为了阻止ROP攻击,对一个应用的代码片段进行随机化。然而当前由于信息泄漏的出现,打破了代码随机化,一个运行程序的代码布局对于攻击者来说不再是不可知的。

5、V8引擎

V8引擎是Chromium浏览器的一部分,V8引擎包含了3个JIT编译器:baseline编译器(快速产生非优化的代码),CrankShaft优化编译器和TurboFan优化编译器。拥有多个JIT编译器可以让JavaScript引擎关注于最常用执行代码的优化工作,这是非常重要的,因为花费在代码优化上的时间会增加整体的运行时间。
JIT引擎把产生的代码放入缓存中,避免持续的重编译相同的方法。代码中最常执行的方法被优化的版本代替。当代码缓冲区到达一定的大小后,通过移除最少最近使用的方法来实现垃圾回收。因为代码缓冲区是只需更新的,JIT编译器通常为有RWX权限的页分配代码缓冲区。这就意味着,不同于静态产生代码,这很难在不影响性能的情况下排除动态产生代码的读和写。

该领域研究现状

近年来,提出了很多针对代码重用攻击的防御方法,这些防御机制大致可以分为两类:第一类是控制流完整性(CFI),第二类是代码随机化。
CFI,阻止攻击者执行静态控制流图(CFG)之外的控制流边界。然而粗粒度的CFI策略存在很多性能上的问题,而且其准确性也和下层的CFG密切相关,而获得一个完全准确的CFG通常是不可能的,尽管能获取到源代码。因此近来在CFI方面的工作关注粗粒度的解决方案,均衡考虑安全性和性能。然而,所有这些解决方案都因为其不准确的CFI策略,可以被成功绕开。
代码随机化的思想用在此类攻击的防御中是十分有效的,近来提出的两种防御方式:Oxymoron和Execute-no-Read(XnR)都关注如何减少或消除内存泄漏的问题。比如Oxymoron目的在于隐藏直接代码和指令中的数据指针。而XnR将所有的内存页(除了一个滑动窗口)都标记为不可访问,从而防止内存页被动态的读取和分解。然而,上面的两种方法仍然很难放置信息泄漏的问题,可以通过多种方法被成功绕过。同时它们很难实际的实现对复杂应用的保护,比如包含just-in-time编译器的Web浏览器。后来,Szekeres提出了一种不同的方法,Code-Pointer integrity(CPI),这种方法将代码指针和非控制数据隔离。接着Kuznetsov对CPI进行了实现,通过把所有的代码指针都放在一个安全的区域,该区域在64位模式下通过虚拟地址空间的偏移量的随机化实现隐藏。然而,Evans使用侧信道攻击成功绕开了这个CPI实现,此部分工作和龚伟刚同学研读的论文相关。
另一方面,代码随机化的解决方案由于内存泄露的问题存在受到了打击,其基本内存是保密的假设不再成立,即一个运行程序的代码布局可以被攻击者得知。可见内存泄漏的问题是十分严重的,因此文章中也在此方面做了很多工作,包括对直接和间接两类内存泄露攻击的区分。此部分工作在下面会详细介绍。

本论文实现目标

本文中,我们关注代码随机化。目标是通过阻止内存泄漏来解决现有使用合理粒度代码随机化的防御方法的缺陷。为了实现这个总目标,我们分为几个小目标。
1、为了得到阻止内存泄漏的方法我们首先需要对内存泄漏进行分析和研究,将信息泄漏源分为直接和间接的内存泄漏。
2、然后我们要呈现出Readactor的设计框架和实现技术;
3、作为第一个实用的细粒度代码随机化防御方法,Readactor要求能够抵抗直接和间接两类内存泄露攻击。
4、解决之前方法的不足。我们的防御方法将一个基于硬件的强化机制结合到新的编译器变换中。该机制能够防止攻击者读取任何代码。特别地,我们在当前的商业处理器中使用虚拟化支持来实现execute-only许可的页。这种支持让我们避免了之前工作的两个重要缺点:1)要求一个可读代码的滑动窗口;2)要求一个传统硬件。

论文核心思想

本文解决了之前防御方法的不足,首次展示了一种实用的,细粒度代码随机化防御方法Readactor。这种方法能灵活的适用于静态ROP攻击和动态ROP攻击,能抵抗直接和间接两种类型的内存泄漏,并且能对静态和动态两种方式产生的代码进行保护。Readactor使用了一种新的基于编译器的代码产生范式,它采用了现代CPU提供的硬件特性来实现execute-only(只可执行)内存;还使用了代码指针隐藏技术来防止信息泄漏给攻击者。

论文主要贡献

1)全面灵活的应对各种ROP攻击
Readactor阻止了所有现存的ROP攻击包括:传统的ROP,没有返回的ROP,动态ROP。更重要的是,Readactor提升了JIT-ROP预防领域的现状,通过利用代码指针隐藏技术来阻止间接内存泄漏。
2)提出了新技术
本文介绍了扩展execute-only内存来保护间接内存泄露的编译器转换。还提出了一种利用硬件加速的内存保护来实现execute-only内存.
3)覆盖静态&动态产生代码
本文首次提出一种技术,既能处理静态编译的代码,也能应对JIT编译的代码。
4)现实和广泛的评价
我们提供了一个全面的Readactor原型实现,并且在复杂真实的软件上测试实施该保护后的性能影响情况。在计算密集型基准上得到平均6.4%的开销。此外,我们提出的解决方法超过了像Google的著名Chrom web浏览器这类复杂程序的基准水平。证明是实际可行的方案。

本文具体工作内容分析

1、区分直接内存泄露&间接内存泄露

首先本文对直接和间接这两种类型的内存泄漏进行了区分。内存泄漏使得之前用于防止代码重用攻击最广泛有效的方式——地址随机化失效。简单的代码随机化,比如ASLR(地址空间布局随机化)通过随机化代码片段的基地址的确加大了ROP攻击的难度。然而现在攻击者可以利用内存泄漏来得知内存布局和机器码的随机化位置,利用这些信息,攻击者可以推断出运行时的指令序列地址,绕开代码随机化的阻挡实现ROP攻击。通常攻击者可以发起直接或者间接内存泄漏攻击。因此本文先对这两种类型的内存泄漏进行分析,通过下图可以更加清晰的看到两者不同:
Figure 1: 直接内存泄漏和间接内存泄漏
Figure 1: 直接内存泄漏和间接内存泄漏

2、Readactor系统框架及核心技术

为了实现目标本文提出了Readactor系统框架。从图中可以看到,这个系统分为两部分,左边是编译部分,右边是运行部分。下面根据Figure 2对系统的核心技术和原理进行详细说明。
Figure 2:Readactor 系统概览
Figure 2:Readactor 系统概览

Compiling部分:Readactor包含三种作用于Compiler的技术,需要在编译器中对代码进行处理,实现相应的功能,包括:
1)代码和数据的分离
2)细粒度的代码地址随机化
3)代码指针隐藏
Runtime部分:Readactor包含两种在运行时的技术,分别用于直接和间接内存泄露攻击:
1)EPT扩展页表技术,是Intel在2008年提出的新型虚拟化特性,属于硬件支撑技术。Readactor用EPT技术在硬件中实现代码页的只可执行许可。下图更加清楚的展现了EPT在一个虚拟内存页映射到一个主机物理页的过程中所扮演的角色。
Figure 3: EPT(Extended Page Tables)
Figure 3: EPT(Extended Page Tables)

上图展示了虚拟内存,客户机物理内存和主机物理内存之间的关系。页表和EPT包含了地址转换过程中的访问许可。在此例中装载的应用包含两页,一个是代码页,标记为execute-only,一个是数据页,标记为可读可写,这些页的许可由compiler和linker设定。标准页表实现虚拟内存地址到物理地址的转换;而EPT相当于在内存转换中增加的一个抽象层,负责虚拟机VM的物理地址(所谓主机Guest的物理地址)到真实物理地址(即host物理地址)的转换。最终一个页的许可情况是由页表许可和EPT许可共同决定的。EPT许可不能被软件绕过。但是只有操作系统作为一个虚拟客户机执行时,才能使用EPT。
2)Tranpolines(跳板)技术,在Data page和Code page之间加了一块跳板,用来隐藏代码指针。有两种类型的Tranpolines:jump tranpolines—用来保护function address; call tranpolines—用来保护call sites。下图更加清楚的说明了如何利用Tranpolines(跳板)这种高水平技术来实现代码指针的隐藏。
Figure 4: Trampolines如何实现代码指针隐藏
Figure 4: Trampolines如何实现代码指针隐藏

首先,我们看到data page拥有readable-writeable许可,code page拥有execute-only许可,表明攻击者不能读到code page上的信息。当我们要通过上图中的Function pointer 1来实现函数调用时,这个执行被重定向到Tranpoline A,然后再由Tranpoline A跳转到真正的子函数Function A. Tranpoline A 是Readactor使用的一块跳板,放置于Data page上的代码指针和code page上的被调用函数之间,里面包含了能跳转到Function A的指令。使得攻击者不能直接通过读取data page获得Function A的指针,只能获得Tranpoline A的指针。同时因为Tranpoline A 位于execute-only的内存上,因此攻击者就算获得了Tranpoline A的起始位置,也不能读取到Tranpoline A里面的内容,从而无法获得Function A的指针,实现了代码指针的隐藏。

》》(未完待续)

0 0
原创粉丝点击