Address Space Layout Randomization(ASLR)是什么?一些攻击,比如returnorientedprogramming(ROP)之类的代码复用攻击,会试图得到被攻击者的内存布局信息。这样就可以知道代码或者数据放在哪里,来定位并进行攻击。比如可以找到ROP里面的gadget。而ASLR让这些内存区域随机分布,来提高攻击者成功难度,让他们只能通过猜测来进行不断试错的攻击(理想状况下),图1为ASLR示例。

ASLR的问题
在出现了某些漏洞,比如内存信息泄露的情况下,攻击者会得到部分内存信息,比如某些代码指针。传统的ASLR只能随机化整个segment,比如栈、堆、或者代码区。这时攻击者可以通过泄露的地址信息来推导别的信息,如另外一个函数的地址等。这样整个segment的地址都可以推导出来,进而得到更多信息,如图2所示,大大增加了攻击利用的成功率。在32位系统中,由于随机的熵值不高,攻击者也容易通过穷举法猜出地址。

如何改进?
主要的改进方法有两种:一是防止内存信息泄露,二是增强ASLR本身。本文主要讨论后者。
1.随机化的粒度可以改进。粒度小了,熵值增加,就很难猜出ROP gadget之类的内存块在哪里。ASLP[1]在函数级进行随机化,binary stirring[2]在basic block级进行随机化,ILR[3]和IPR[4]在指令级。[3]将指令地址进行随机化;而[4]把指令串进行重写,来替换成同样长度,并且相同语义的指令串。
2.随机化的方式可以改进。Oxymoron[5]解决了库函数随机化的重复问题:原先假如每个进程的library都进行fine-grained的ASLR,会导致memory开销很大。该文用了X86的segmentation巧妙地解决了这个问题;并且由于其分段特性,JITROP[6]之类的攻击也很难有效读取足够多的memory。Isomeron[7]利用两份differentlystructured but semantically identical的程序copy,在ret的时候来随机化executionpath,随机决定跳到哪个程序copy,有极大的概率可以让JIT-ROP攻击无效。
3.随机化的时间(timing)可以改进。假如程序中存在能泄露内存的漏洞,那这种传统的、一次性的随机化就白费了。所以需要运行时动态ASLR。[8]解决了fork出来的子进程内存布局和父进程一样的缺陷。其思路是在每次fork时都进行一次随机化。方法是用Pin进行taint跟踪,找到ASLR之后要修复的指针并进行修复。为了降低把数据当成指针的false positive,一个daemon进程会跑多次来提取出重合的部分。
Remix[9]提出了一种在运行时细粒度随机化的方法。该方法以basic block为单位,经过一个随机的时间对进程(或kernel module)本身进行一次随机化,如图3所示。由于函数指针很难完全确认(比如被转换成数据,或者是union类型),该方法只能打乱函数内部的basic blocks。该方法的另一个好处是保留了代码块的局部性(locality),因为被打乱的basic blocks位置都靠得很近。打乱后,需要update 指令,以及指向basic block的指针,来让程序继续正确运行。假如需要增加更多的熵值,可以在basic blocks之间插入更多的NOP指令(或者别的garbage data)。

另一种方法[10]是用编译器来帮助定位要migrate的内存位置(指针),并且在每次有输出时进行动态随机化。该方法对于网络应用比如服务器,由于其是I/O-intensive的应用,可能会导致随机化间隔极短而性能开销巨大。(作者单位为Florida State University)


特别声明:本站注明稿件来源为其他媒体的文/图等稿件均为转载稿,本站转载出于非商业性的教育和科研之目的,并不意味着赞同其观点或证实其内容的真实性。如转载稿涉及版权等问题,请作者在两周内速来电或来函联系。