APP下载

基于异常控制流识别的漏洞利用攻击检测方法

2014-01-01王明华应凌云冯登国

通信学报 2014年9期
关键词:漏洞内存代码

王明华,应凌云,冯登国

(1. 中国科学院 软件研究所 可信计算与信息保障实验室,北京 100190;2. 中国科学院大学,北京 100049)

1 引言

软件漏洞是信息系统安全的主要威胁,各大软件厂商在不断改进和完善软件开发质量管理,但软件漏洞问题仍无法彻底消除。根据Secunia发布的漏洞数据[1],可以看到应用软件漏洞占绝大多数,并且漏洞数量逐年增多。此外,应用软件漏洞种类多样,包括Flash漏洞、浏览器漏洞、文件格式漏洞等,涉及到 Adobe Reader、Microsoft Office Word、Adobe Flash Player等被广泛使用的软件。

为了缓解应用软件漏洞带来的危害,新型操作系统引入了地址空间随机化(ASLR)和数据执行保护(DEP)等安全机制,一定程度上抑制了针对应用软件和系统漏洞的利用攻击。但是,攻击者仍然能够通过精妙的利用构造,找到绕过这些安全机制的方法,通过劫持控制流实施利用攻击。为了应对这些新安全环境下的利用攻击,安全人员需要及时地发现攻击威胁,以便快速做出响应,避免造成损失。近年来,学术界提出了控制流完整性检测、污点分析等分析方法,来对程序执行过程中的异常控制流进行检测,取得了一定的效果。控制流完整性检测方法[2],通过在CFG图中构造控制流转移的合法目标地址集合,在控制流转移发生时,校验目标地址是否在合法的集合内,并以此作为攻击检测的依据。此种方法依赖CFG,无法解决动态生成代码相关的恶意控制流转移问题,如JIT Spraying攻击等。动态污点分析方法[3~5]将程序输入标记为污点源,通过监控程序动态执行过程,在污点数据被异常使用时产生警告。由于污点分析需要细粒度地监控程序执行,使得系统运行效率开销很大,同时污点分析方法本身存在一些局限性,会使得检测结果存在一定范围的误报率和漏报率。在工业界,如FireEye[6]等安全厂商提出了通过API行为拦截,利用一定的启发策略来判定恶意行为的方法。然而,这些检测方法在函数级别开展分析,但是漏洞利用攻击可能发生在指令级别,仅通过API拦截无法获知指令级的异常控制流转移,导致此类方法检测漏洞利用攻击的能力有限。

本文提出了一种针对应用软件漏洞利用攻击的检测方法:通过对目标程序加载的二进制模块进行静态分析,获得函数边界和导出属性等,构建初始的合法控制流转移边界;结合在程序动态执行时实时维护的控制流转移记录,构建完整的控制流转移安全轮廓。将程序执行过程中,转移至此轮廓之外的控制流转移,判定为具有利用攻击威胁的异常的控制流转移。本文方法通过识别异常控制流转移,在攻击代码执行之前,检测到利用攻击。本方法能够准确检测包括动态生成代码在内的恶意控制流转移的攻击;另外,本方法不依赖于任何漏洞和攻击代码的先验知识,同时具有较为理想的运行效率,可以作为漏洞攻击实时检测的解决方案。

本文方法的贡献与创新点如下。

1) 提出了一种通过检测异常控制流转移判定漏洞利用攻击的方法,结合静态和动态分析手段,构造完整的程序安全执行轮廓,识别安全轮廓之外的异常控制流转移,检测漏洞利用攻击。该方法较传统利用污点分析等细粒度数据流分析方法具有较高的准确性和较理想的运行效率。

2) 提出了一种检测来自于动态生成代码的利用攻击的方法,通过分析内存的页面属性、数据相似性等,对动态生成代码的合法性进行判断,从而识别转移至非法动态生成代码的控制流。该方法解决了控制流完整性校验等方法无法处理的诸如 JIT Spraying攻击的检测问题。

3) 实现了漏洞利用攻击检测原型系统,并通过对Word、IE、Flash Player等8个实际漏洞进行检测实验,验证了本文方法的有效性。实验表明,本方法不仅具有很高的检测准确性,同时还具有较小的运行开销,可用于漏洞利用攻击实时检测。

2 相关工作

漏洞利用攻击检测相关研究主要包括基于动态污点传播的方法和基于控制流完整性的方法2大类。在动态污点传播方面,相关的漏洞攻击检测系统有 Argos[7,8]。Argos将网络数据作为污点源,在动态执行过程中监控是否有sink函数使用污点。该系统能够用来检测0 Day漏洞攻击,能够支持针对Windows 7等操作系统上应用软件的漏洞攻击。该分析系统依靠污点分析实现,由于污点方法自身存在的局限性,所以难以保证监控结果的准确性,具有一定的误报和漏报率,同时具有较大的运行开销。相似的检测系统还有 TaintCheck[4]、Panorama[9]等。

基于控制流完整性校验(CFI,control flow integrity)的方法同样可以用于检测漏洞利用攻击。该方法[2]首先由Abadi等人提出,通过构造CFG图中所有间接控制流转移的合法目标地址的集合,在控制流转移发生时校验目标地址是否在合法的集合内,以此可以作为攻击检测的依据。然而,对于控制流转移结构复杂的程序而言,构造 CFG的准确性难以保证,这会对检测结果有一定的影响。

binCFI[10]也是基于CFI方法实现,提出了间接控制流转移目标地址的完整性校验方法。这些目标地址包括地址指针常量,经过算术运算得出的程序地址,以及函数返回地址等。对这些目标地址的校验是基于静态分析的结果,会引入一定的误判,例如,方法没有验证函数返回的合法性,可能通过导致覆盖函数地址控制执行流的情况。这种异常情况需要结合动态执行信息来进行判断。

Total-CFI[11]同样利用CFI手段来判断间接控制流转移的合法性,是动态分析方法。该方法利用了影子栈,监测来自在用户态和内核态的控制流异常攻击,系统具备较理想的运行效率;但是,该系统在检测间接函数调用目标时粒度过粗,会带来一定的误判,同时对动态生成代码分析的较弱,无法检测通过JIT Spraying等实施的漏洞攻击。

CCFIR[12]通过重写二进制文件来加入控制流转移校验的过程,也具备漏洞检测的能力。CCFIR在二进制文件中添加新的springboard节区,用以随机存放该模块中所有间接控制流转移目标地址,并改写间接控制流转移调用处代码,使得在这些代码执行时,首先跳转至springboard验证合法性。该方法能够抵御传统的ret-to-libc和ROP攻击,但是无法识别动态生成代码有关的控制流合法性。FPGate[13]提出的方法与 CCFIR相似,但更关注函数调用的合法性。FPGate和CCFIR等方法基于二进制重新技术(binary rewriting)来实现,需要用户重新部署新的二进制模块,适用性较差。

3 问题描述和方法框架

Windows 7等操作系统采用了ASLR和DEP等安全机制,传统的函数地址覆盖、异常处理覆盖等漏洞利用手段已经难以奏效。要成功利用Windows 7等平台上应用软件的漏洞,首先需要突破ASLR和DEP等机制的防护,常见的方法包括 ROP[14]和内存喷射(spraying)[15]。ROP能够通过重用内存中已加载模块中的代码片段,达到修改shellcode数据所在内存页面属性的目的,使数据执行保护失效;内存喷射技术通过在内存某段区域中大量部署shellcode,从而在ASLR导致地址不确定的情况下,也能保证利用攻击具有较高的成功率。图1中给出了2种利用攻击过程。

通过这些攻击方式可以发现,漏洞得以成功利用是由于程序执行过程中发生了异常控制流转移。在图 1(a)中,shellcode存放在 0x0c0c0c0c、0x7c345678、0x7c349654等地址处的指令序列为ROP 链中的garget。攻击者首先利用ROP 链,将shellcode所在内存区域处变为可执行,再将控制流转移至shellcode,实施攻击。从图中可以看出,漏洞利用攻击所依赖的异常控制流转移发生在函数返回时,此时的控制流不应该转移至 0x7c345678处的ROP garget,而是应该转移至call eax调用时压入的下条指令地址处。在图 1(b)中,攻击者将vtable虚函数表中第 3个虚函数被篡改为0x0c0c0c0c,并且在内存中喷射出很多包含了攻击代码的内存区域,在函数调用call[eax+0x8]时,目标地址不应是0x0c0c0c0c处的动态生成代码,而应该是由ecx所指定类中的虚函数。

根据上述分析,本文提出一种通过检测异常控制流转移判定漏洞利用攻击的方法。方法架构如图2所示。本方法通过对二进制目标程序进行静态分析,构造初始的安全执行轮廓;在动态监控程序运行阶段,识别动态生成代码,对安全执行轮廓进行维护。结合构建的完整安全执行轮廓,检测函数调用、函数返回、间接跳转等控制流转移的合法性,将异常控制流转移判定为漏洞利用攻击,进而捕获完整的攻击步骤。本文方法不但能够检测由于违反静态 CFG图中限定的控制流转移所导致的利用攻击,而且支持动态生成代码相关的利用攻击。

图1 ROP和内存喷射利用原理示意

本文接下来将针对如何构建安全执行轮廓,如何判定漏洞利用攻击,以及如何提取漏洞利用攻击步骤进行详细阐述。

图2 漏洞利用攻击检测方法架构

4 安全执行轮廓构建

安全的控制流转移轮廓,需要确保程序所运行的所有控制流转移指令能够转移至合法的目标地址。Abadi等人提出的控制流完整性检验方法[2],通过静态获得的 CFG图,构造所有控制流转移的合法目标地址。然而,程序在运行过程中可能出现动态生成代码,例如:

1) 一些第三方软件通过加壳等方式进行保护,在软件运行时,首先开辟一块具有可执行属性的内存区域,然后将代码拷贝至区域中,程序首先执行此段动态生成的代码,然后进行后续的执行;

2) 某些程序在运行过程中,可能在函数起始地址等处添加hook,在此函数执行时,程序将跳转至存放在另一个具有可执行权限的内存区域中,执行hook处理代码,如在 IE 8进程启动并加载IEShims.dll模块时,将在一些模块函数入口处添加hook,劫持这些函数的运行,以完成所需要的处理;

3) 另外,某些应用程序支持JIT(just in time)代码运行,例如Flash程序,可以通过Action Script编写Flash程序,在程序运行时,Flash代码被加载到可执行属性的内存页面中,通过JIT方式执行。

上述动态生成代码执行情况,Total-CFI[11]、binCFI[10]等基于CFI的方法均无法处理。为此,本文通过静态分析构造初始安全执行轮廓,在程序动态执行阶段,识别合法的动态生成代码区域,构建完整的控制流转移安全轮廓,从而不但能够判定模块之间的控制流转移的完整性,而且能够处理动态生成代码的安全控制流转移问题。

4.1 安全执行轮廓构定义

本文识别程序运行过程中所有可执行代码,将这些代码所在模块和函数作为安全执行轮廓,并基于此,判定程序运行时控制流转移的安全性。

为了阐述方便,做出如下定义。

1) 代码块tb:每一个代码块由若干条顺序执行的指令组成,其中,仅最后一条为控制流转移指令,如call、ret和jxx等。它是进行控制流转移检测的最小检测单元。

2) 加载模块m:是指待分析程序在导入表中引入的模块,或者在运行时动态加载的可执行模块;将加载模块构成的集合记为ML,即ML= {m}。

3) 模块函数fm:是指存在于模块m中的函数;将所有模块函数的集合记为FL,FL= {fm|m∈ML}。

4) 动态生成代码(DGC,dynamic generated code):在程序运行过程中,在具有可执行内存属性页面上、非加载模块中的代码;即DGC={tb|tbinPe&&tbnot inm, ∀m∈ML,Pe为具有可执行属性的页面}。本文将 DGC所在内存区域视为一个 DGC模块mdgc,将DGC中可以被调用的一个执行单元记为DGC函数fdgc。具体DGC模块和函数的提取方法见4.3节。

5) 安全执行轮廓(CFSO,control flow safety outline):具体包括模块轮廓和函数轮廓。其中,模块轮廓为M,M=ML∪{mdgc};函数轮廓为F,F=FL∪{fdgc}。

安全执行轮廓的构建分为2个阶段:首先依赖二进制分析程序自身,构造初始的安全执行轮廓,此轮廓是静态CFG图中限定的所有执行函数FL和加载模块ML;然后,通过动态监控程序执行,识别所有DGC模块{mdgc}和DGC函数{fdgc},对安全执行轮廓进行补充和维护。下面,首先讨论初始安全执行轮廓构建的过程,然后讨论如何通过动态监控目标程序执行,构建完整的安全执行轮廓。

4.2 初始安全执行轮廓建立

依靠二进制目标程序自身构造初始安全执行轮廓。主要包括获得二进制目标程序自身和其加载模块的属性,以及这些模块中所有函数信息。

对于函数,需要通过反汇编二进制模块获取每一个函数的起始地址。除此之外,还需要确定模块中函数是否具有外部调用属性,即此函数是否允许被其他模块代码调用,例如模块A中代码调用模块B中函数,那么,此函数应该被模块B导出。为此,将函数分为2类,分别是外部调用函数和内部调用函数。具有外部调用属性的函数,可以被除自身模块之外的其他模块调用,例如模块导出的函数,C++类实例中具有 public属性的虚函数等;具有内部调用属性的函数,则只能够被自身模块调用。

从模块的导出表和重定位表来获得具有外部调用属性的函数。通过导出表,可以获得此模块中所有导出的函数。通过重定位表,获得地址需要重定位的函数。具体方法是:依次扫描每一个重定位表项,如果该表项的数值与模块基地址的和在模块代码段的范围之内,那么就视其为一个地址需要重定位的函数。本文将这类函数和导出函数认为是具有外部调用属性的函数。最后,模块中除去这些外部调用属性函数之外的函数,认为是具有内部调用属性的函数。

通过分析函数外部调用属性,能够有效防范篡改虚函数地址的漏洞利用攻击。由于在虚函数表中的函数地址需要被重定位,所以,所有虚函数都被划归为外部调用函数。如果类实例的某个虚函数被覆盖为某恶意地址,并且此恶意地址不在此模块的外部调用函数集合之内,那么能够检测到这一异常控制流转移。

对于漏洞程序运行所依赖的模块,按照PE格式解析模块文件,获得模块加载基地址和大小,是否具备随机化属性,以及导入、导出、重定位表等数据项的内容。由于程序在运行时可以动态加载模块,对这些模块,虽然可以动态解析模块文件,获得上述模块和其中所有函数属性信息,但是这将使得系统运行效率受到较大的影响。所以,对系统中所有模块文件进行预先分析,并将分析结果保存到文件中。在后续动态分析判定过程中可以直接读取,从而提高了系统运行效率。

4.3 安全执行轮廓动态维护

为了处理 DGC相关的控制流转移,需要动态识别DGC模块和DGC函数,并将其加入到安全执行轮廓中。虽然可以通过对二进制程序在运行时采取细粒度的跟踪分析,来获得DGC模块和DGC函数在内存位置,提取 DGC数据,但是这需要较大的运行开销。相反,选择在DGC执行时,识别DGC模块和DGC函数。所用算法伪代码如下。

算法1IdentifyDGC(M,F,ML,FL,tb)

//该算法识别DGC模块和DGC函数,并加入到模块轮廓M和函数轮廓F中

输入:当前的模块轮廓M和函数轮廓F,进程加载模块集合ML,模块函数集合FL,当前执行的tb

输出:最新的模块轮廓M和函数轮廓F

该算法在每一个tb执行时被调用。函数参数ML、FL是通过构建初始安全执行轮廓时得到的。算法检测当前执行代码是否在已加载模块内(第 1行),若不在,则说明当前正在执行DGC,接下来提取DGC模块和DGC函数(第2行之后)。

由于系统随机化不仅针对加载模块,而且包括例如TEB、PEB等关键数据结构、栈和堆分配地址的随机化,所以,攻击者在考虑到利用攻击的稳定性,会通过喷射的方式保证攻击的成功率。为此,充分利用这一特性,识别 DGC模块,并区分其合法性和非法性。

本文将内存区域认为是具备相同属性的相邻内存页面的集合。那么,在利用攻击发生时,寄存器eip值一定在某个存放了shellcode等恶意代码的具有可执行属性的内存区域之内。这个区域相邻的内存区域,一定也存放了与此内存区域高度相似的恶意代码数据。这些内存区域是攻击者为了保证利用攻击的稳定性,大量喷射操作的结果。本文通过检测相邻内存区域中数据的相似度,来判断控制流转移至 DGC的合法性。此检测过程由算法 1中check_attacky实现。算法伪代码如下。

算法2check_attacky(eip)

//该算法检测eip所在的DGC是否具有攻击特征

输入:当前程序执行的pc

算法首先获取进程内存空间中所有内存区域RgnList,然后找到当前eip指向的区域RgnCur,以及与之相邻的2个区域RgnFmr和RgnLtr。如果这些区域不都具备可执行属性,那么当前内存区域不是喷射而来。否则,计算出要执行的指令地址在当前内存区域中的偏移,并且验证在相邻内存区域上相同偏移处的数据相似性。算法中,设置了一个检测窗口N,用于表示在各个内存区域中读取的字节数量,并用变量d表示数据相似性。如果d高于某一个阈值T,即认为高度相似,那么再反汇编当前内存区域的指令序列,验证指令序列中是否存在疑似shellcode的指令,最后返回验证结果。

由于shellcode的形式具有多样性,例如被多次加密或存在多个攻击指令片段等,使得验证shellcode疑似指令具有一定的误报率;另外,验证shellcode会对分析运行效率造成一定影响,所以,在相邻内存区域都具备可执行属性,并且相同偏移处数据高度相似之后,再验证shellcode疑似指令。这种策略的可靠性在于,攻击者为了提高漏洞利用的成功率,会通过内存喷射等手段在内存页面中部署尽可能多的攻击代码,使得相邻的内存区域中的数据具有高度的相似性。

由于shellcode需要重定位获得加载地址,以及可能需要实时获得执行所需API地址,所以通过检测重定位指令和一些访问进程数据结构的敏感指令序列,来判定当前指令数据疑似shellcode的程度。其中,重定位指令包括call/pop、fnstenv/pop、fxsave/pop等常见指令组合,敏感指令包括获得当前进程控制块、获得当前进程加载模块的指令序列等。

如果经过上述检验,此内存区域不具备攻击属性,那么将此内存区域作为合法的 DGC模块,并获取此区域的基地址和大小作为DGC模块的基地址和大小,将此DGC模块加入到维护的可执行模块的集合中。在程序执行过程中,此段DGC可能重复执行,集合元素的唯一性保证了此DGC模块在可执行模块集合中仅出现一次。相反,如果检验发现此内存区域具有攻击属性,那么当前转移至此的DGC控制流非法,判定为漏洞利用攻击。

对于 DGC函数,由于无法像模块函数那样获知 DGC函数的起始地址,所以,当程序控制流由非DGC模块转移至某段DGC时,将此次控制流转移的目标地址视为 DGC函数起始地址,而在控制流由 DGC模块返回至非 DGC模块时,视为此段DGC函数执行结束,并将在DGC模块之间执行的所有代码块视为一个DGC函数体。并且,将DGC函数视为具有外部调用属性的函数。DGC函数示意如图3所示。

图3 DGC函数示意

5 漏洞利用攻击判定

根据构建的安全执行轮廓,对程序运行过程中发生的间接控制流转移进行验证,将不合法的控制流转移判定为漏洞利用攻击。为此,对3种间接控制流转移进行分析:通过call指令进行的函数调用;通过ret执行进行函数返回;以及通过jmp执行进行程序跳转。下面分别就这3种控制流转移的验证方式进行讨论。

5.1 函数调用的检测方法

间接调用的目标地址仅能在运行时确定,需要根据构建的安全执行轮廓来验证目标地址的合法性。如果间接函数调用目标地址不在当前调用模块之内,首先验证目标地址是否是函数的起始地址,再验证此目标函数是否具有外部调用属性;如果目标函数被所在模块导出,则还需验证调用模块是否导入了此模块。如果间接函数调用目标在当前调用模块内,仅验证目标地址是否是当前模块的函数,不限定此函数的属性。只有通过验证的间接函数调用,才被认为是合法。上述验证过程的算法伪代码如下。

算法3chk_call(dst,mc)

//检测call指令目标地址的合法性

输入:call指令的目标地址dst,call指令所在模块的代码段mc

工作Total-CFI[11]同样检测call控制流转移合法性的问题,但与本文方法不同的是,它仅仅验证call的目的地址是否是一个函数的起始,而不关心这个函数是否具有外部调用属性,这导致验证结果不够准确,可能会产生漏报。另外,此系统还无法处理DGC相关的控制流转移问题。

5.2 函数返回的的检测方法

控制流可以通过函数返回指令进行转移。正确的函数返回的目标地址,应该是此函数被调用时压入栈中的地址。在函数返回时,如果验证发现返回地址不合法,可以判定控制流被劫持,即有异常控制流转移。

与Total-CFI系统类似,通过影子栈来实现返回地址合法性的验证。为每一个线程维护一个影子栈,在函数调用发生时,在对应的影子栈中压入返回地址;在函数返回时,在对应影子栈中验证压入的地址与此返回地址是否一致。考虑到异常处理、setjump/longjmp等特殊情况,返回地址可能不在栈顶,但是一定在栈中。所以,在本文中仅验证返回地址是否在影子栈中,并将栈顶到此项之间所有的项弹出影子栈。如果未在栈中,则判定为异常控制流转移。

另外,与Total-CFI不同的是,本文还考虑了另一种特殊情况:push addr、ret。这种ret实际上起到call的功能。由于addr值是由push 压入,而非函数调用call压入,所以在影子栈中无法找到。本文通过额外为每一个线程维护一个 push栈来记录压入的值,在函数返回 ret发生时,首先查看该线程的影子栈,如果没有在栈中找到返回值,则在push栈中寻找。如果找到,将此值至栈顶的元素全部弹出。否则,则说明当前 ret可疑,可能使程序控制流转移至危险位置。

5.3 跳转转移的检测方法

跳转可分为直接跳转和间接跳转。对于直接跳转,目标地址一定在自身模块内,无需检测。对于间接跳转,需要检测目标地址的合法性。

对于jmp [C+idx*idx’]模式的跳转,其中,idx、idx’为寄存器或立即数,如果C值在程序代码段或者数据段范围内,那么认为此C值是程序中某个函数地址表的起始,其中的每个地址项占用4个字节,此跳转指令正是通过地址表C获得偏移idx*idx’处的目标地址。本文将此类跳转指令合法目标地址集合记为S

即从地址表C开始,依次查看每一表项的值是否在当前模块的代码段mc范围内,并将符合此条件的值加入到S中,直至遇到不满足此条件的地址项为止。在此类jmp执行时,如果目标地址不在其合法地址S中,将此指令的执行判定为异常控制流转移。

对于其他间接jmp跳转指令,目标地址理论上可以是内存中任意位置,但通过对实际应用程序的分析,发现合法的间接跳转指令的目标地址都应在本模块内。所以,将跳转至自身模块代码段之外的间接跳转,判定为异常的控制流转移。

6 漏洞利用攻击步骤捕获

在捕获到利用攻击所需的异常控制流转移之后,捕获后续漏洞利用攻击的步骤。这些攻击步骤有助于分析人员掌握攻击细节,对评估漏洞的危害性,以及制定防御方案等具有重要的意义。

当识别到异常控制流之后,开始单步执行目标程序,记录程序执行指令和调用的函数。对于执行的指令,记录每一条指令类型以及操作数的值;对于调用的函数、记录参数和返回值。通过监控进程创建、用户创建、文件操作、网络访问等系统API调用,能够捕获“下载并运行”、“添加新用户”等恶意行为。

通过这些记录,分析人员能够还原漏洞利用攻击的所有细节。例如,如果漏洞利用采用了 ROP方式,可以获知为了构造 ROP 链,利用代码重用了哪些指令片段,攻击载荷所在内存区域如何获得可执行属性,以及攻击载荷所进行的恶意操作。再如,通过检测利用攻击点所在内存区域相邻的内存区域的属性,以及比对这些区域的数据相似性,可以获知内存喷射漏洞的喷射粒度和喷射范围等信息,评估此漏洞利用的成功率等。安全分析人员可以利用这些信息,对软件漏洞的危害性进行评估,制定漏洞补丁方案,或者生成检测工具所需的漏洞特征等。

7 实验评估

基于硬件模拟器 QEMU 1.6.1[17,18]实现原型系统ECfield (enhanced control flow integrity based exploit detector),并利用8个实际漏洞利用攻击样本对本文的系统进行实验评估。在实验中,原型系统运行在配备了四核 3.20 GHz Intel Core i5-3470 CPU、8 GB内存、250 GB硬盘的Fedora Core 13计算机上。实验漏洞攻击样本运行在QEMU Guest系统中。各个样本运行的 CVE编号、漏洞程序和所运行的系统环境如表1所示。

7.1 系统实现

ECfield包括静态分析和动态分析2个组件。在静态分析组件中,对二进制加载模块和模块内的函数进行分析,构建初始的安全执行轮廓;在动态分析组件中,根据执行状态,对安全执行轮廓进行维护,同时,对控制流转移进行验证,将不合法的控制流转移判定为利用攻击,并提取攻击步骤。

构建初始的安全执行轮廓时,通过在IDA Pro 6.1[19]中编写IDA Python插件,提取二进制漏洞程序和其加载的动态链接库中的所有模块和函数属性等信息。模块信息包括加载地址、大小、导入表、导出表和重定位表、随机化属性等数据信息;函数属性信息包括所属模块,函数起始地址相对模块加载地址的偏移,函数的外部调用和内部调用属性等。本文将这些分析结果以文件形式保存,在动态分析阶段,系统通过读入文件内容到内存中,进行后续分析和验证操作。

在 QEMU中添加进程识别、线程识别、模块识别等功能模块,分别获得系统中新创建的进程、每一个进程所创建的线程、以及每一个进程加载的模块。在系统运行过程中,根据当前代码块所在内存地址,判定是否为 DGC。如果属于DGC,遍历进程虚拟空间描述符 VAD,获得相邻内存区域,判定这些区域的数据相似度。当数据高度相似时,通过验证当前执行的DGC指令序列是否具有shellcode特征,来判定当前DGC是否具有攻击属性。如果具有攻击属性,则直接判定为利用攻击;否则,提取DGC模块和DGC函数,加入到安全执行轮廓中。在验证相邻内存区域数据相似度时,将检测窗口长度N设置为32 byte,并且相似度阈值T设置为80%。另外,从 Metasploit[20]中提取验证过程中所用到的shellcode疑似指令特征。

表1 实验样本

在系统运行过程中,为目标程序中每一个线程维护一个影子栈,验证所有发生在用户态的函数返回的合法性。当间接函数调用发生时,通过安全执行轮廓,验证目标地址是否是目标模块中具有外部调用属性的函数。当间接跳转时,根据跳转指令的模式,验证目标地址是否在合法的跳转地址集合内、或是否在当前模块代码段范围之内。如果验证不合法,则判定为控制流转移异常。

在检测到异常控制流转移后,ECfield Hook进程创建、用户添加、网络访问等系统API,并开启对目标程序的单步跟踪分析。通过改变 QEMU代码块译码逻辑,使其每个代码块仅包含一条指令,实现单步执行的效果。在每个代码块执行时,ECfield检测当前地址是否是被Hook函数的起始地址。如果是,就从栈中读取函数参数和返回地址。在被Hook的函数返回时,ECfield读取QEMU Guest系统的eax寄存器获得函数返回值。单步执行的指令信息和函数调用信息,最终保存在文件中,以便供分析人员还原攻击细节。

7.2 利用攻击检测结果

本文选取了近年具有较严重威胁的漏洞,对实验系统进行评估。这些漏洞涉及用户广泛使用的软件,如IE、Adobe Reader、Word、Flash Player等,漏洞的利用攻击类型也涵盖多种,包括ret-to-libc、SEH exploit、ROP 攻击、Heap Spraying、JIT Spraying等。实验中检测到的各个样本程序的异常控制流转移指令地址、控制流转移指令、攻击类型等信息如表2所示。

从上述漏洞利用攻击中可以看到,CVE-2012-0158这一针对Word 2007的利用攻击仍然是通过直接覆盖函数返回地址,采用 ret-to-libc的方式实现的。此攻击能够成功的原因在于,即使DEP机制已经部署到Windows 7系统中,但是由于Word自身没有开启DEP,使得栈中的shellcode仍然能够得以执行。

另外,CVE-2010-2883、CVE-2011-0611、CVE-2007-4607等样本展示了Spraying和ROP结合的攻击方式。通过喷射将攻击代码大量部署在内存中,能够有效突破内存地址随机化安全机制,同时利用 ROP和 JIT 的方式来保证将攻击代码所在内存区域可执行。此种攻击方法可以同时绕过DEP和ASLR机制。

实验表明,本文的系统不但可以检测 ret-tolibc、SEH exploit等传统利用攻击,也能成功检测到APT攻击所应用的ROP、JIT Spraying、Spraying结合ROP等方式的复杂漏洞利用攻击。

7.3 案例分析

表2 样本程序分析结果

本文挑选 CVE-2013-2551和 CVE-2007-4607 2个案例来对 ECfield的检测过程和效果进行详细阐述。这2个漏洞分别利用了目前在APT等漏洞利用攻击中广泛使用的 Spraying结合 ROP、JIT Spraying攻击方式。同时,2个漏洞程序在运行过程中都存在动态代码执行的情况。本文的系统能够准确地识别合法的动态指令代码场景,并对异常动态代码执行情况进行准确判定。

案例1CVE-2013-2551漏洞利用攻击

此漏洞是由于 IE 8浏览器没有对 dashstyle.array的长度做出正确的验证,导致整数溢出。在本实验中,样本运行在Windows 7专业版系统中。

程序在运行时,共有256次执行动态生成代码的情况,其中包括执行Hook代码和Flash JIT 代码等。ECfield准确地识别了这些正常的动态代码执行的情况,没有产生漏报和误报。

程序的异常控制流转移发生在mshtml模块中,偏移为0x1bc545处的指令:call [eax+0x8],目标地址是 0x7c348b05,该地址在 msvcr71.dll中。由于ECfield在每一次间接函数调用时,会对控制流转移的合法性进行判断,此次调用的目标地址不是一个外部调用函数的起始地址,ECfield将此次控制流转移判定为不合法。

通过ECfield,可以进一步获悉此漏洞利用的攻击过程。msvcr71.dll是加载到IEXPLORE进程中的非随机化模块,模块中地址 0x7c348b05处开始的指令片段是:xchg eax, esp; ret;通过这两条指令来切换栈区域,栈顶变为 0x0c0c0c0c,并且通过 ret返回到存放在新栈顶处的地址0x7c341748,继续执行后续的 ROP片段。从系统单步跟踪利用攻击点之后的指令序列可知,0x0c0c0c70处存放了shellcode,攻击者修改了所在页面的执行属性,最终跳转至shellcode执行。另外,ECfield通过检测相邻的内存区域,发现它们不但具有相同的执行属性,同时相同偏移处的数据相似度达到 100%。由此判定,此漏洞利用攻击采用了Spraying结合ROP的攻击方式。

案例2CVE-2007-4607漏洞利用攻击

此漏洞利用采用了JIT Spraying的方式进行攻击。攻击样本通过加载一段恶意的Flash视频文件,使得其中的Flash脚本运行,脚本将shellcode喷射到大量内存区域中,随后通过触发IE ActiveX插件的漏洞,促使控制流跳转至内存中某段shellcode,进而实施攻击。此样本运行在Windows 7专业版系统中,Flash Player的版本为10.3.4。

由于在程序执行过程中Flash 的JIT指令所在的内存区域具有可执行属性,所以通过JIT Spraying能够将嵌入到Flash中的shellcode直接喷射到大量的具有可执行属性的内存中,攻击者不用额外构造ROP链来绕过DEP保护,因此,攻击者可以通过此攻击方式,同时绕过 ASLR和 DEP;而且由于CFI方法[2]无法处理动态执行代码执行的合法性,所以此攻击方式也能够绕过Total-CFI[11]、binCFI[10]提出的检测方法。

Flash JIT代码是程序运行过程中生成的动态代码。在每一次控制流执行至JIT代码模块时,ECfield确定此代码模块所在的内存区域,检测与之相邻的内存区域的可执行属性和相同偏移处的数据相似性。当高度相似时,进一步通过反汇编当前JIT 代码模块中指令序列,检测是否有高度疑似shellcode的指令,以此判定Flash JIT代码相关的控制流转移的合法性。

在此案例中,ECfield共发现17 828次正常的JIT 代码相关的控制流转移,在每次提取相关DGC模块和DGC函数之后,ECfield将它们加入到安全执行轮廓中。异常的程序控制流转移发生在 ntdll模块偏移为0x465f7的指令call ecx处。此函数调用的目标地址本应为SEH链中的异常处理例程函数,但是实际目标地址却为0x0c3f0101。0x0c3f0101处数据是 Flash JIT 动态生成代码。该地址所在的内存区域为[0x0c3f0000 ~ 0x0c3fffff]。在与之相邻的内存区域[0x0c3e0000 ~ 0x0c3effff]和[0x0c400000 ~0x0c40ffff]中,相同偏移处的数据与当前内存区域中的数据相似度达到 100%。同时,0x0c3f0101开始的汇编指令序列中,包含了访问当前进程PEB、获得模块列表LDR地址和获得关键API内存地址等疑似shellcode指令序列。由于相邻内存区域中数据高度相似,并且当前目标指令序列具有疑似攻击指令,因此,ECfield将之判定为异常的控制流转移。通过随后的单步跟踪发现,shellcode头部有大量重复的nop和cmp al, 0x35指令。这些滑板指令保证了控制流转移至shellcode的成功率。

7.4 时间运行开销

本文利用攻击检测方法具有较小的运行时间开销。在原型系统ECfield中,测量在样本开始运行至检测到利用攻击发生时的时间间隔t,同时,也在原生 QEMU模拟器中运行同样的攻击样本,并测试这一时间间隔t’,具体数据如图4所示。ECfield平均运行时间开销约为原生QEMU系统的2.1倍。由此可见,本文的方法具有较高的利用攻击检测效率,能够用于漏洞攻击的实时检测。

在运行效率上,本文的实验系统比利用污点跟踪分析实现的分析系统,如Argos漏洞攻击检测系统[7],具有较明显的优势。污点分析方法需要跟踪每一条指令来处理污点状态的传播过程。要达到理想的效果,分析粒度需要在字节级别,这导致运行时间开销大概增长 3~50倍[4,5]。另外,Argos仅采用直接数据依赖的污点分析,真实漏洞利用中还包含大量有关污点数据的间接数据流依赖和控制流依赖的情况,这使得这些基于污点分析实现的检测系统,很难保证检测效果的准确率。

图4 ECfield与原生QEMU运行时间开销对比

8 局限性

本文方法对实际漏洞利用攻击具有较好的检测效果,但是也存在着一些局限性。首先,本文方法重点关注针对应用程序的漏洞利用攻击检测,无法检测发生在内核中的利用攻击。其次,在间接函数调用时,验证目标函数是否具有外部调用属性,对于某些call-to-libc类型的利用来说,如果call的目标恰好是 call指令所在模块导入的函数(如kernel32模块中的WinExec),并且直接通过此函数执行恶意行为,本文方法将认为此函数调用是正常的,造成漏报。由于Windows 7等操作系统中已经加入SafeSEH、ASLR和DEP等安全机制,攻击者很难仅通过一次call调用来绕过这些安全机制,完成所有的攻击步骤,所以此种利用方法很难应用在实际的漏洞攻击中。为了检测此种类型的攻击,可以重点关注如WinExec、CreateProcess等函数,通过在这些函数调用时检测函数参数是否包含恶意数据识别攻击。

9 结束语

本文提出一种基于异常控制流识别的漏洞利用攻击检测方法,能够在恶意攻击代码执行之前,检测到攻击发生。通过对二进制目标程序静态分析和动态执行监测,构建完整的安全执行轮廓,并限定控制流转移的合法目标。在函数调用、函数返回和跳转等控制流转移发生时,检测目标地址的合法性,将异常控制流转移判定为漏洞攻击,并捕获完整的攻击步骤。为验证本文方法的正确性,本文实现了基于异常控制流转移检测的漏洞利用攻击原型系统,并对若干实际高危漏洞进行实验。实验表明,本文的方法能够准确检测到利用攻击,并具备良好的运行效率,可以作为漏洞利用攻击的实时检测工具。

[1] Secunia[EBOL]. http://secunia.com/vulnerability-review/.2014.

[2] ABADI M, MIHAIBUDIU, ERLINGSSON U. Control-flow integrity[A]. Proceedings of the 12th ACM conference on Computer and Communications Security[C]. Raleigh, NC, USA, 2005.340-353.

[3] BOSMAN E, SLOWINSKA A, BOS H. Minemu: the world’s fastest taint tracker[J]. Recent Advances in Intrusion Detection, 2011, 6961:1-20.

[4] NEWSOME J, SONG D. Dynamic taint analysis for automatic detection, analysis, and signature generation of exploits on commodity software[A]. Network and Distributed System Security Symposium[C].San Diego, California, USA: Internet Society, 2005.

[5] SCHWARTZ E L, AVGERINOS T, BRUMLEY D. All you ever wanted to know about dynamic taint analysis and forward symbolic execution (but might have been afraid to ask)[A]. IEEE Symposium on Security and Privacy[C].Oakland, CA, USA, 2010.317-331.

[6] FireEye[EB/OL]. http://www.fireeye.com/.2014.

[7] Argos[EB/OL]. http://www.few.vu.nl/argos/.2014.

[8] PORTOKALIDIS G, SLOWINSKA A, BOS H. Argos: an emulator for fingerprinting zero-day attacks for advertised honeypots with automatic signature generation[J]. Proceedings of the 1st ACM SIGOPS/EuroSys European Conference on Computer Systems 2006[C]. New York, NY, USA: ACM, 2006.15-27.

[9] YIN H, SONG D, EGELE M. Capturing system-wide information flow for malware detection and analysis[A]. Proceeding of the 14th ACM Conference of Computer and Communication Security[C]. Alexandria, VA, USA, 2007.116-127.

[10] ZHANG M W, SEKAR R. Control flow integrity for COTS binaries[A]. Proceedings of the 22nd USENIX Conference on Security 2013[C]. Berkeley, CA, USA, 2013.

[11] PRAKASH A, YIN H, LIANG Z K. Enforcing system-wide control flow integrity for exploit detection and diagnosis[A]. 8th ACM Symposium on Information, Computer and Communications Security[C].Hangzhou, China, 2013.311-322.

[12] ZHANG C, WEI T, CHEN Z F. Practical control flow integrity &randomization for binary executables[A]. The 34th IEEE Symposium on Security & Privacy[C]. San Francisco, CA, USA, 2013.559-573.

[13] ZHANG C, WEI T, CHEN ZF. FPGate: The Last Building Block For A Practical CFI Solution[R]. Technical Report For Microsoft BlueHat Prize Contest, 2012.

[14] ROEMER R, BUCHANAN E, SHACHAM H. Return-oriented programming: systems, languages, and applications[J]. ACM Transactions on Information and System Security, 2012,15(1).

[15] DING Y, WEI T, WANG TL. Heap Taichi: exploiting memory allocation granularity in heap-spraying attacks[A]. Proceedings of the 26th Annual Computer Security Applications Conference[C]. New York,NY, USA: ACM, 2010.327-336.

[16] Heap FengShui[EB/OL]. https://www.blackhat.com/presentations/bheurope-07/ Sotirov/Presentation/bh-eu-07-sotirov-apr19.pdf.2014.

[17] BELLARD F. Qemu, a fast and portable dynamic translator[A]. Proceedings of the 14th USENIX conference on Security [C]. Baltimore,MD, USA, 2005.

[18] WANG MH, SU PR, LI Q. Automatic polymorphic exploit generation for software vulnerabilities[A]. 9th International Conference on Security and Privacy in Communication Networks[C]. Sydney, Australia.2013.216-233.

[19] IDA Pro[EB/OL]. https://www.hex-rays.com/products/ida/,2014.

[20] Metasploit[EB/OL]. http://www.metasploit.com/,2014.

猜你喜欢

漏洞内存代码
漏洞
笔记本内存已经在涨价了,但幅度不大,升级扩容无须等待
“春夏秋冬”的内存
创世代码
创世代码
创世代码
创世代码
三明:“两票制”堵住加价漏洞
漏洞在哪儿
高铁急救应补齐三漏洞