王丰峰, 张涛, 徐伟光, 孙蒙

陆军工程大学,江苏 南京 210001

摘要:控制流劫持攻击是一种常见的针对计算机软件的攻击,给计算机软件安全带来了巨大的危害,是信息安全领域的研究热点。首先,从攻击代码的来源角度出发,阐述了进程控制流劫持攻击的相关研究;其次,根据控制流劫持攻击技术的发展现状,基于不同防御思想介绍了近年来国内外的相关防御技术;最后对控制流劫持攻防技术发展趋势进行总结和展望。

关键词: 软件安全 ; 控制流劫持攻击 ; 控制流完整性 ; 随机化

中图分类号:TP309.2

文献标识码:A

doi: 10.11959/j.issn.2096−109x.2019058

1 引言

随着信息技术的不断发展,计算机软件在人们的日常生活中扮演着越来越重要的角色。然而,由于软件开发者的疏忽以及编程语言固有的局限性,安全漏洞在计算机软件中普遍存在。自1988年Morries 利用缓冲区溢出漏洞编写蠕虫病毒瘫痪了大量网络计算机以来,网络攻击,尤其是控制流劫持攻击给国家和社会带来了巨大的经济损失。控制流劫持攻击是一种常见的针对计算机软件的攻击,通常可以通过缓冲区溢出等漏洞改变进程的控制流从而进行恶意操作。针对控制流劫持攻击,研究人员提出并实现了许多防护技术,攻防双方相互依赖,不断发展演进,形成了如图1所示的攻防对抗演进过程。本文总结了控制流劫持攻击的基本原理和最新进展,同时依据防御思想重点介绍了相关防御技术,并进行了分析比较。因为现阶段的防御技术还存在性能开销大、兼容性差等方面的问题,不少技术尚未进行广泛部署。因此,本文总结分析控制流劫持攻击与防御的相关技术,这对研究人员设计更加合理实用的防御技术具有一定的理论价值和实际意义。

图1 劫持控制流攻防对抗演进过程

2 进程控制流劫持攻击技术研究现状

控制流劫持攻击通过构造特定攻击载体,利用缓冲区溢出等软件漏洞,非法篡改进程中的控制数据,从而改变进程的控制流程并执行特定恶意代码,达到攻击目的。根据攻击代码的来源,可以将控制流劫持攻击划分为代码注入类攻击和代码重用类攻击。

2.1 代码注入类攻击

在代码注入攻击中,攻击者通常利用进程的输入操作向被攻击进程的地址空间注入恶意代码,并且通过覆盖函数返回地址等手段,使进程非法执行注入的恶意代码,从而劫持进程控制流达到攻击目的。代码注入类攻击成功的根本原因在是冯·诺依曼体系中,指令和数据不加区别混合存储在同一个存储器中,导致计算机可能将数据误当作指令执行。为了抵御代码注入攻击,研究人员提出了数据执行保护(DEP,data execution protection)的防御措施,通过将进程地址空间中的可写部分设置为不可执行,在很大限度上抵御了代码注入类攻击。

2.2 代码重用类攻击

与代码注入类攻击不同,代码重用攻击不需要攻击者向进程地址空间中注入恶意代码,它仅利用程序或共享库中已有的指令来完成攻击,因此能够顺利绕开DEP保护机制。这种攻击模式被证实具有图灵完备性,但危害大、易扩展。其中,最为常见的是面向返回的编程(ROP)攻击。ROP 攻击可以利用进程已有的代码片段(称为gadget),通过栈溢出等漏洞将各个gadget的地址和其他相关数据相结合,精心构造payload,使进程在执行函数返回时,劫持控制流跳转到指定gadget,从而进行恶意操作。ROP 攻击的基本过程如图2所示,步骤2和步骤3就是构造恶意gadget的过程,当进程在步骤6进行函数返回时,则执行攻击者指定的步骤7~步骤9。由于ROP攻击使用了以ret指令结尾的gadget链导致其容易被检测出来。Bletsch等提出了JOP攻击,以jmp或者call指令来串联gadget;Checkoway等提出利用pop-jmp指令来代替ret指令,完成重用攻击。这些ROP攻击的变种使ROP攻击更加灵活隐蔽,加大了检测难度。

图2 ROP攻击流程

2.3 代码重用类攻击的改进

尽管传统的代码重用攻击主要针对x86平台,但是近年来,研究人员在ARM、SPARC等平台下也实现了对计算机软件的代码重用攻击,证实了代码重用攻击在多个平台上的广泛存在性甚至提出了利用中间语义REIL实现一个平台无关的gadget搜索框架,使跨平台的ROP攻击更加容易,进一步增加了计算机应用软件防御代码重用类控制流劫持攻击的难度。

由于 ROP 攻击需要攻击者知道 gadget 的地址,因此地址空间布局随机化(ASLR,address space layout randomization)等在进程运行前提供防御措施的静态防御技术,可以有效抵御传统的ROP攻击。为了克服传统ROP攻击的缺陷, Snow等提出了JIT-ROP(just-in-time ROP)的攻击技术,它通过即时代码重用恢复内存布局,击败了细粒度运行前随机化技术。相比于传统的ROP技术,JIT-ROP攻击可以反复使用内存泄露的方法动态映射应用程序的内存布局,同时发现gadget以及API函数,并利用这些gadget进行攻击。实验证明,JIT-ROP 可以绕开任意粒度的随机化。JIT-ROP 攻击方法的诞生揭示了运行前随机化无法在进程运行时动态引入随机性的致命缺陷。JIT-ROP技术最大的特点是寻找并利用gadget的过程都在程序运行时动态进行的,其攻击形式多样,能够击败ASLR技术。

此外,Linux系统中父进程fork()中的子进程总是享有和父进程同样的地址空间布局,本文将这种模式称为fork-oriented模式。而许多C/S架构的网络模型都在使用这样的运行模式,这会导致BROP(blind ROP)攻击。BROP攻击由Bittau等提出,是JIT-ROP攻击的扩展模式。BROP攻击可以在不获得被攻击进程二进制文件的前提下进行远程攻击,给网络中的计算机系统造成巨大危害。攻击者可以通过不断向子进程进行嗅探和猜测来获取关于地址空间布局的知识并找到足够的 gadget 进行恶意攻击。Bittau 等设计了一个完全自动化的BROP攻击工具,成功绕过了64 bit的ASLR技术,实现了对nginx的BROP攻击。

3 进程控制流劫持防御技术研究现状

随着控制流劫持攻击技术的不断发展,其对软件安全造成的威胁也日趋严重。因此研究人员提出许多相应的防御技术。总体上讲,根据防御技术引入的时间将控制流劫持防御技术分为运行前静态防御和运行时动态防御两大类。

3.1 运行前静态防御技术

运行前静态防御技术一般是通过修改编译器或加载器在进程运行前进行缓冲区边界检查、栈保护、替换链接库、随机化等保护措施,来确保运行时控制流不被篡改。数据执行保护通过区分数据和代码的不同权限可以有效阻碍代码注入类攻击。StackGuard是GCC编译器的一个补丁,编译时它通过在缓冲区和返回地址间加入随机canary值保护用户栈。Libsafe是在进程运行前替换易受攻击的库函数,从而保护 strcpy、printf等存在危险的函数。FormatGuard通过比较提供给 printf 函数实际参数的数量与格式字符串调用参数的数量来抵御基于格式错误的控制流劫持攻击。此外还有很多类似的技术,在进程运行前加入防御机制以提高软件安全性。然而,这些防御方式留给攻击者充足的时间进行探索和攻击。

JIT-ROP和BROP等攻击通过不断嗅探和猜测,利用进程运行时产生的动态信息,绕开了静态防御的保护,从而篡改进程控制流。这些运行时动态攻击方式甚至可以在没有二进制文件的情况下进行远程攻击,所以运行前防御技术已经无法抵御这种攻击技术。运行时动态攻击的出现,再次打破了攻守双方的平衡,使软件防御技术研究人员将目光转向了运行时动态防御技术上。

3.2 运行时动态防御技术

运行时动态防御技术则在进程运行过程中即时地进行安全保护,防止控制流被非法篡改。根据进程运行时动态防御思想的不同,本文可以将进程运行时动态防御技术分为两大类:基于可信计算的运行时防御技术和基于主动变换防御思想的防御技术。

3.2.1 基于可信计算的运行时防御技术

可信计算通过确保系统始终在可信状态下迁移来确保系统安全,基于可信计算的动态防御技术则通过将进程控制流与预期的正常控制流进行对比,从而保证进程运行过程始终可信。

基于可信计算的运行时防御技术的代表是控制流完整性(CFI,control flow integrity)。CFI最早由Martín等[20]提出。CFI基于动态可信度量,分析程序正常控制流,并依此构造出针对进程的控制流图(CFG,control flow graph)。CFI技术的关键是限制进程运行过程中的控制流转移,从而使进程的控制流只在其原有 CFG 所限定的范围内,保证进程运行过程可信。具体做法是通过分析程序的控制流图,获得间接转移指令目标的地址,形成一个白名单,然后在进程运行过程中,核对转移目标指令是否在正常控制流的白名单中。由于JIT-ROP等针对Linux进程的控制流劫持攻击会改变程序的正常行为,从而违背原有的控制流图。因此CFI能够抵御运行时动态控制流劫持攻击。

在CFI提出后,该技术得到了研究人员的广泛研究,各种CFI防御技术层出不穷。CFI可以根据划分目标指令的精细程度分为细粒度CFI和粗粒度CFI。严格意义上讲,最早Martín提出的CFI技术是细粒度CFI。细粒度CFI仔细检查每个间接转移指令的目标地址,并与正常控制流图进行比对,确保每条转移指令只能转到其限定的范围内,来保证程序控制流的完整性。Mashtizadeh等提出的CCFI会识别所有影响程序控制流的对象,并且计算这些对象的消息认证码,从而进行指针加密。通过在使用每个控制流元素之前检查消息认证码,系统可以保证运行时控制流不被非法篡改。Criswell 等提出了KCoFI,这是一种在操作系统内核上的 CFI, KCoFI在验证进程控制流完整性的基础上,加入一个对进程进行动态监视的中间软件层,以进一步保护一些关键数据结构。然而,对进程指令进行精细的检查会造成巨大的性能开销。为了降低系统性能开销,粗粒度的CFI选择放宽检查条件,将同一类转移指令整理到一起进行验证。例如, CCFIR利用一个专用的“Springborad section”来实现间接分支转移,没有实现对每一条指令进行精细检查;binCFI将间接转移指令进行分类,同一类转移指令归纳到同一目标集合中,粗化检查粒度,提高进程运行效率。由于没有对每一条转移指令进行检查,粗粒度CFI会导致系统抵御攻击的能力下降,攻击者依旧可以针对粗粒度CFI 进行代码重用攻击。Göktas 等利用 entry point(EP)gadget和call site(CS)gadget成功实现了对粗粒度CFI的攻击;Conti等提出了名为StackDefiler的系列攻击,分别利用堆上的漏洞、用户空间和内核空间切换时存在的漏洞以及泄露影子堆栈的地址,完成了在有 CFI 保护的前提下针对堆栈的攻击,同时也击败了DEP和ASLR保护技术;Carlini等利用对非控制数据的攻击,提出了名为CFB的攻击技术,并且证明 CFB 能够对精细的 CFI 进行有效攻击。2015年,Otgonbaatar指出,即便获得了细粒度的控制流完整性,也存在被攻击的风险,这使CFI技术的防御有效性受到了质疑。

为了减少CFI的性能开销,目前有研究人员开始利用硬件来辅助实现CFI。Pappas等设计了名为kBouncer 的基于硬件的CFI,该技术利用Last Brach Register监视进程中的跳转指令,以防止进程的异常控制流。Qiu 等提出了利用一种基于轻量级加密的体系结构(LEA-AES)对间接跳转指令和返回地址进行加解密,从而保证了进程控制流的完整可信。Zhang等设计了HCIC技术,该技术利用海明距离匹配和线性加解密机制,通过特定硬件的辅助,在不对编译器进行修改、不增加新的指令集的条件下,实现了低开销的CFI。

CFI 是建立在对被保护程序深入理解基础上的防御技术,因此往往需要源代码或调试信息。在运行动态监测时,CFI 无法完美刻画进程的CFG,因此可能导致限制程序正常运行或允许程序执行非法操作。在运行时CFI需要比对跳转指令的目标地址,导致巨大性能开销。由于存在以上种种问题,虽然CFI已提出十多年时间,仍然没有在实际系统中得到广泛部署应用。

表1给出上述控制流完整性防御技术的对比。

3.2.2 基于主动变换防御思想的运行时防御技术

主动变换防御通过持续地、动态地变化来迷惑攻击者,从而增加其攻击成本,降低其攻击成功概率。基于主动变换防御的运行时防御技术则是在进程运行过程中不断引入随机性和多样性,打破攻击者构造传统攻击链所依赖的各种有利条件,加大攻击者攻击成功的概率。

基于主动变换防御思想的运行时防御技术的代表是内存布局随机化。随机化思想最早是在1997 年由 Forrest 等提出的,通过引入多样性和随机性来提高计算机系统的稳健性。内存布局随机化通过不断改变进程内存布局,实现进程攻击面的随机性变换,从而消除了攻击者的不对称优势,增加了攻击者的攻击难度。此外,由于每一计算机进程在系统中的内存布局不同,运行时内存布局随机化还能阻碍攻击在网络中的扩散。

Pax ASLR是早期随机化技术的代表,其基本原理如图3所示。它会对ELF可执行文件地址空间中运行时才映射的动态共享库位置等映射区域进行随机化操作。当攻击者需要知道进程中的gadget地址时,由于内存布局被随机打乱,因此加大了攻击者的攻击难度。同时当进程被编译为位置无关代码时,Pax ASLR还能随机化代码段的基地址,进一步增加了攻击者攻击成功的难度。

图3 Pax ASLR基本原理

目前,在许多流行的操作系统中部署了 Pax ASLR 技术,以提高操作系统的安全性。然而, Pax ASLR是一种粗粒度的随机化技术,随机化熵值低并且只随机化段基地址,因此容易遭受暴力攻击和信息泄露攻击。细粒度随机化技术不仅随机化了段基地址,而且打乱进程段内对象的相对偏移,增大随机化引入的熵值,从而有效抵御暴力攻击和信息泄露攻击。作为一种解决传统粗粒度随机化缺陷的技术,细粒度随机化技术被研究者广泛采用,并被认为可以进一步提高进程的安全性。

然而,JIT-ROP和BROP攻击的提出,使运行前的细粒度随机化技术在面对运行动态攻击时没有了用武之地。针对JIT-ROP和BROP攻击的一种有效保护方法是在运行时对地址空间进行再随机化操作。运行时再随机化技术通过在进程运行过程中不断对进程地址空间进行再随机化布局,减小了单一地址空间布局的存在时间,缩短攻击者的攻击周期,使攻击者无法掌握足够的知识来完成一次完整的攻击,运行时随机化示意如图4所示。

图4 运行时随机化示意

Giuffrida等提出了操作系统中细粒度随机化技术的设计和运行时再随机化的思想,并在Minix3微内核中成功部署了运行时内核级地址空间布局随机化技术。Chen等提出了JIT-ASR技术,该技术使用虚拟内存管理,可以在运行时通过修改代码地址的虚拟页码和页表来不断改变程序的地址空间。侯宇分析了ROP攻击的原理,并在此基础上设计了一种称为Chameleon的防御机制,Chameleon在虚拟地址转换为物理地址中间加了一个中间层,从而将取指异或访存和进程地址空间随机化有机结合起来。Chen等提出了Remix技术,通过LLVM编译器框架将代码函数分割成许多基本块,并对进程地址空间中的函数基本块进行基于时间模型的运行时再随机化。这些运行时随机化技术大都需要修改内核模块来支持进程再随机化操作,实现难度大,兼容性有限,并且都选择基于时间的再随机化,会造成一些不必要的性能开销。Hawkins等提出的Mixr运行时再随机化系统可以在不依赖源代码以及不修改系统内核和加载器等组件的基础上进行,然而该技术由于在运行时需要反复进行动态链接导致性能开销过大。

上述运行时随机化技术都是基于时间的再随机化模型,即每隔一段时间进行一次随机化操作。由于运行时地址空间再随机化操作会给程序性能带来影响。在没有受到危险操作时,过于频繁的随机化会带来巨大的性能开销,而随机化频率过低则给攻击者留下攻击的机会。基于时间的再随机化模型无法消除这一矛盾。Bigelow 等提出了实时再随机化(TASR)技术,在输入/输出系统调用之间引入随机性,从而使攻击者获得的内存信息无效。TASR 提出了一种将随机化与潜在的运行时信息泄露相结合的方法,视成对的输入/输出操作为危险操作,当有成对输入/输出操作时,则触发随机化。由于只在面临危险操作时进行随机化,TASR 减少了不必要的随机化开销。雷啸改进了TASR技术过于宽泛的危险操作的判断,提出了安全敏感区的概念,只有当进程write 操作访问安全敏感区时才在后续 read 操作前触发随机化,进一步减少了性能开销。Morton等提出了当攻击者在内存中公开了可能有用的可执行gadget时,才触发防御机制,以确保攻击者不能利用这些字节来劫持运行时进程的控制流。这些基于潜在风险的随机化方案,减少了不必要的再随机化操作,对于大部分进程而言,该方案要优于基于时间的再随机化方案。

针对BROP攻击,Lu等提出的RuntimeASLR技术对父进程fork出的子进程进行地址空间布局进行再随机化,从而抵御复制探测攻击。RuntimeASLR的技术核心是一个自动的、整体的指针跟踪机制,Lu认为这是未来进行指针识别和运行时动态保护的有用工具。然而,RuntimeASLR技术只适合nginx这类fork-oriented程序,并且只支持x86体系架构。

除了在运行时对内存布局进行随机置换外,还有研究人员提出加载多个进程映像并在运行时进行随机切换,从而使攻击者获取的运行时内存信息无效。Davi等提出了Isomeron技术,在一个虚拟地址空间中,Isomeron 同时加载了两份不同的进程映像。在程序运行时,一旦发生了函数调用,就随机决定接下来执行哪个程序副本。Williams-King等提出了称为Shuffler 的防御机制。Shuffler 在几毫秒内对进程地址空间进行运行时再随机化,并“原子地”从一个随机化的代码副本切换到另一个随机化的代码副本。Williams-King等还考虑了Shuffler本身可能存在的攻击面,通过对自身的地址空间进行再随机化,可以减小防御工具本身攻击面对安全性带来的影响。由于 gadget的地址在每个副本中不一样,且攻击者也无法预测接下来运行哪个副本。因此这样的方法能有效抵御JIT-ROP和BROP攻击。

表2给出进程运行时再随机化技术的对比。

表3给出进程控制流劫持运行时动态防御技术的总体对比。

4 结束语

在信息安全领域中,如何抵御控制流劫持攻击一直是一个热点问题,尤其Snow提出JIT-ROP攻击之后,以这种新型控制流劫持攻击为基础的攻击模式不断被提出,对计算机进程构成巨大威胁。BROP 攻击的提出更是突破了传统控制流劫持攻击对目标二进制的依赖,实现了“盲的”控制流劫持攻击,使传统的软件静态被动防御机制变得形同虚设。

控制流劫持攻击是计算机软件面临的巨大威胁,随着新型代码重用类攻击的诞生和演化,控制流劫持攻防对抗不断升级。控制流劫持攻击技术的发展也面临着许多挑战和新的发展方向。首先, JIT-ROP和BROP攻击所采用的方法并不高效,需要多次尝试和足够时间来“积累知识”。然而,攻击时间越长,防御者越可能对攻击做出反应。因此快速获取成功完成攻击所需要的信息是未来控制流劫持攻击的研究重点。其次,在二进制文件不可得的情况下进行控制流劫持攻击是一个难点。而BROP攻击则揭示了fork-oriented应用进程所存在的安全漏洞,为今后攻击二进制信息不可得的应用进程拓宽了思路。最后,随着ARM等其他平台的广泛应用,针对这些平台的防御技术不断升级。借鉴现有控制流劫持攻击的研究成果,实现对其他平台的控制流劫持攻击也值得研究人员关注。目前,运行时动态防御技术是抵御JIT-ROP和BROP攻击的有效手段,笔者依据其背后防御思想的不同分成了基于可信计算和基于主动变换防御思想的运行时防御技术。

基于可信计算的CFI技术通过限制程序的控制流来保证程序被正确地执行。然而,细粒度的CFI 也被研究人员证实存在防御缺陷;进程动态控制流图难以精确刻画;同时CFI还存在性能开销大、依赖调试信息等问题。如何在低性能开销的基础上,构造正确合理的CFG是制约CFI技术进一步发展的瓶颈,也是CFI未来主要的一个研究方向。与此同时,结合硬件来降低CFI开销,并提高 CFG 覆盖率和准确率也是一个值得探索的方向。

基于主动变换防御的运行时动态随机化技术,通过在进程内部引入随机性来抵御运行时动态代码重用攻击。运行时再随机化通过不断对进程地址空间进行再随机化布局,改变程序自身的属性,打断了攻击者对进程地址空间的原始认知,使攻击者先前积累的有关进程地址空间的知识无效化,从而抵御代码重用攻击。相比 CFI,运行时随机化能够有效阻碍攻击的扩散,同样也值得深入研究。内存布局随机化技术会使进程出现“带伤运行”的情况,存在造成进程非正常运行的可能性,如何降低随机化操作对进程带来的“伤害”,具有重要的现实意义。此外,运行时内存随机化对进程的保护能力与其随机化粒度之间的关系,随机化最合理的触发时间等问题仍然缺乏相应的研究,这使运行时随机化的发展陷入无法在保护力度和性能损耗之间取得一个最为合理平衡的困境,因此对运行时内存随机化进行费效评估也是一个值得研究的方向。

最后,现阶段的控制流完整性和地址空间随机化技术大多是针对x86平台,在ARM等其他平台上鲜有类似研究。然而,如第2节所述,控制流劫持攻击在许多平台中都可以实现,并且同样可以达到执行任意恶意代码的目的。因此在ARM 等其他平台上的或者跨平台的运行时动态保护技术同样亟待研究和解决。

作者简介

王丰峰(1994− ),男,江苏昆山人,陆军工程大学硕士生,主要研究方向为系统安全。

张涛(1973− ),男,甘肃泾川人,博士,陆军工程大学教授,主要研究方向为操作系统安全、数据库安全、智能终端软件安全等。

徐伟光(1984− ),男,安徽宿州人,博士,陆军工程大学讲师,主要研究方向为移动目标防御、密码学、区块链等。

孙蒙(1984− ),男,山东齐河人,博士,陆军工程大学副教授,主要研究方向为网络安全与机器学习、智能语音处理等。

声明:本文来自网络与信息安全学报,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。