APP下载

基于动态分析的控制流劫持攻击检测

2021-06-03吴小王刘露平

关键词:漏洞指令应用程序

吴小王, 方 勇, 贾 鹏, 刘露平, 王 炎

(1.四川大学网络空间安全学院, 成都 610065; 2. 四川大学电子信息学院, 成都 610065)

1 引 言

网络空间是一个没有硝烟的战场,从1988年的Morris蠕虫病毒到2017年的WannaCry勒索病毒足以可见网络空间安全的严峻态势. 据CNVD[1]最新的收录漏洞类型统计,应用程序漏洞占比高达58.45%,并且漏洞数量在逐年增多. 越来越多的高级持续性威胁(Advanced Persistent Threat,APT)利用应用程序漏洞执行破坏行为[2],对网络空间安全造成巨大的威胁. 尽管各大软件厂商在不断改进和完善软件开发质量管理,但软件漏洞问题仍无法彻底消除.

应用程序漏洞的利用方式多种多样,而控制流劫持攻击是最常见的一种. 控制流劫持攻击允许攻击者破坏程序的控制数据,通常将执行流重定向到攻击者自己的注入代码. 通过执行恶意代码能够完全控制程序和系统,造成极大的危害. 目前的操作系统中部署了地址空间布局随机化(Address Space Layout Randomization,ASLR)、数据执行保护(Data Execution Protection,DEP)、结构化异常处理安全校验(Safe Structured Exception Handling,SafeSEH)等安全机制,一定程度上缓解了控制流劫持攻击对软件和系统的危害. 但是,因为系统环境的多样性,攻击者仍然能够找到绕过这些安全机制的方法. 因此,如何快速高效地发现攻击威胁并及时采取应对措施一直是学术界的研究热点.

由Abadi等人于2005年提出的控制流完整性CFI(Control Flow Integrity)是目前防御控制流劫持攻击的主要技术[3]. CFI的核心思想是获取程序间接转移指令的合法目标并以此构造应用程序的控制流图CFG(Control Flow Graph),强制程序在CFG的范围内运行,能有效地防御控制流劫持攻击. 自提出CFI后,对控制流劫持攻击防御的研究有很大的推进作用,出现了如binCFI[4]、CCFI[5]为代表的粗粒度的CFI;为提高CFI防御能力的上下文敏感的CFI[6],基于数据约束的vCFI[7],操作系统内核层面的KCoFI[8],专门针对ROP攻击的ROPecker[9],随机选择特定跳转进行验证的RCFI[10].

动态污点分析[11]是检测漏洞攻击的另一种主要技术,该技术跟踪程序数据在程序内部的传播,分析程序数据是否处于敏感位置,如常见的函数返回地址,从而检测控制流劫持攻击.

CFI策略虽然能够有效的防御控制流劫持攻击,但是难以在实际环境中部署. 其主要原因有两点:(1) 是CFG的构造困难,完整的CFG构造需要依赖程序源码,对于复杂的程序而言更是难以实现. 虽然没有源码情况下通过逆向分析等技术也可以构建CFG,但是对于采用了加壳[12]、混淆[13]等保护技术的二进制程序,构建CFG难以实现;(2) 是需要检查程序中的每一个间接控制转移,细粒度的检测会引起非常大的开销. 此外,动态污点分析技术在实际检测中存在过污染、欠污染等问题,所以效率较低且精度不高.

针对上述问题,本文提出了一种新的检测控制流劫持攻击的方法:在分析控制流劫持攻击原理的基础上,总结了控制流劫持攻击的行为特征,然后基于二进制插桩技术,通过动态分析应用程序的异常行为,来检测控制流劫持攻击. 与现有的动态污点分析技术和基于CFI策略的控制流劫持攻击检测方法相比,本文方法解决了二进制文件分析需要依赖源码[14]和修改二进制文件的问题,因此具有良好的移植性;另外,所有的检测分析仅在程序运行时进行,不需要静态分析和预处理的过程,具备良好的性能开销,可以方便地部署于各种系统环境中.

2 控制流劫持攻击研究

文献[15]总结了控制流劫持攻击的基本流程(如图1). 一个完整的控制流劫持攻击包含以下5个步骤:构造特定的攻击载体;触发并利用应用程序中的内存破坏漏洞;劫持程序的控制流;绕过DEP、ASLR等安全防护;最后控制程序执行流转向恶意代码,实现漏洞攻击.

图1 控制流劫持攻击流程图

2.2 控制流劫持攻击行为

2.2.1 执行恶意代码 执行恶意代码主要有代码注入和代码复用两种方式. 注入的恶意代码被称为shellcode,一般布置到应用程序的栈空间或者堆空间中. 栈空间用于存放函数参数的值、局部变量的值和函数调用保存的栈帧信息,正常程序不会从栈空间解析指令执行,常见的程序漏洞如缓冲区溢出[16],则会将恶意代码布置到栈空间中执行. 堆是程序运行过程中动态使用的内存空间,用于存放数据,也用于存放动态生成的指令,因此应用程序存在堆空间执行指令的情况.

攻击者除了利用自己构造的恶意代码,还有可能利用程序本身的代码,这种利用方式称为代码重用技术[17],如常见的ROP[18]攻击. ROP攻击利用程序本身的指令片段,这些指令片段称为gadget,每个gadget由ret指令结尾. 通过ret指令将分散的指令片段连接起来,能实现与shellcode相同的功能.

ASLR技术增加了ROP构造的难度,DEP技术使得注入代码无法执行. 因此,代码注入通常与代码复用相结合,首先使用ROP关闭shellcode所在空间的数据执行保护,然后执行shellcode.

2.2.2 造成程序异常 实际的漏洞利用过程中构造的攻击载体一般是针对特定的操作系统和目标程序,而现实中的系统环境多种多样,因此有不少的漏洞攻击会因为环境不同致使应用程序出现内存访问异常甚至崩溃的情况.

漏洞攻击除了被动触发程序异常,还有主动触发异常并利用异常的情况. 当应用程序出现异常,Windows系统下会调用结构化异常处理函数SEH(Structured Exception Handling,)进行异常处理. 图2展示了SEH链表结构.

图2 SEH链表Fig.2 SEH chain

SEH链表的每一个节点都包含Next和Handler两个成员,其中,Handler指向具体的异常处理函数,Next则指向SEH链表的下一个节点,最后一个节点的Next指向为0xFFFFFFFF. 攻击者可以通过触发异常,然后覆盖SEH链表中的Handler地址来劫持程序的控制流,间接地破坏了SEH链表的完整性.

本文通过对控制流劫持攻击原理的研究,分析了在不同的漏洞利用攻击情况下程序的异常行为. 提出了基于动态分析的控制流劫持攻击检测方法,该方法通过动态获取程序运行时信息,针对不同的程序异常行为分别制定检测方法.

程序的内存空间可以分为模块地址空间(程序加载的库文件和可执行程序本身)、栈空间和堆空间等3个区域. 栈空间主要存放的是函数调用时相关的信息,并不会存放代码指令,所以若发现函数执行流程跳转到栈中,则说明存在漏洞攻击行为. 如果不位于栈空间,则可能是位于堆空间中的恶意代码执行. 由于堆空间可能执行应用程序动态生成的代码,因此不能直接判定为恶意代码执行. 但是,通常在执行堆空间恶意代码前会使用ROP关闭shellcode所在内存空间的数据执行保护,因此,可以通过检测ROP防御部分堆空间恶意代码执行.图3为栈执行检测流程图.

图3 栈执行检测

程序执行过程中,获取当前线程的栈空间范围,如果执行的指令地址位于栈空间范围内,则检测到栈执行.

3.2 ROP攻击检测

文献[18]表明程序本身的一些指令片段可以构造出图灵完备的代码. ROP攻击可以利用程序本身的代码片段执行一些函数的功能,比如调用VirtualProtect函数改变内存空间的可执行权限,使得堆空间中的恶意代码能够执行,或者仅仅使用ROP就完成攻击行为. 图4为ROP攻击检测流程图.

图4 ROP攻击检测Fig.4 ROP attack detection

ROP攻击利用的指令片段称为gadget,这些gadget一般由几条指令组成,并以ret指令结尾,ret指令让这些gadget联系在一起,通过顺序执行这些gadget完成一系列功能操作.

程序正常执行过程中函数调用与函数返回一般是匹配的,虽然存在特殊的ret指令与call指令不匹配的现象,但不会出现连续的ret与call不匹配的现象. 文献[18]表明实际的ROP攻击至少有17个连续的gadget,而程序正常执行最多可能存在10个连续的gadget. 因此,为了减少误报率和漏报率,节省时间开销,将连续出现的11个ret异常识别为ROP攻击,具体检测流程如图5,通过构造影子栈,检测到11个连续的异常ret指令,判定为ROP攻击.

KiUserExceptionDispatcher函数是Windows系统下异常处理的起点,该函数有两个参数PEXCEPTION_RECORD和PCONTEXT,分别记录程序异常的具体信息和程序发生异常时的上下文信息. 控制流劫持攻击中程序异常分为以下两种情况:(1) 是攻击失败造成的异常;(2) 是攻击者为了利用SEH造成的异常. 对于第二种异常情况,程序在进行异常处理前SEH链表中的handler已经被恶意数据覆盖,导致SEH链表不再具备图2所示的完整结构. 因此,需要在KiUserExceptionDispatcher函数被调用时获得程序异常的具体信息和检查SEH链表的完整性. SEH异常检测流程如图5.

图5 SEH异常检测Fig.5 SEH detection

当捕获到KiUserExceptionDispatcher函数调用时,首先判断异常类型. 如果异常类型是“访问无效地址”,直接判定为SEH异常; 如果不是,则接着检查SEH链表的完整性,如果SEH链表不完整则判定为SEH异常,否则,继续应用程序的异常监控.

在程序动态运行过程中,通过以上3种方法同时对程序的异常行为进行监控,结合程序运行时信息,实现对控制流劫持攻击的检测以及控制流劫持攻击地址定位和类型判断.

Pin[19]是Intel公司开发的用于动态分析的二进制程序插桩工具,通过及时编译技术在程序原有代码中插入分析代码,从而获取程序动态运行时信息.相较于基于QEMU虚拟环境的动态分析方式,基于Pin的动态分析技术能够直接在应用环境中使用. 因此基于Pin工具设计了控制流劫持攻击检测系统CFHADS(Control Flow Hijacking Attack Detection System). 图6为CFHADS系统架构图.

图6 CFHADS系统架构Fig.6 System structure of CFHADS

CFHADS主要由动态信息提取模块和动态检测2个模块组成. 其中,动态信息提取模块获取应用程序运行时信息以供动态检测模块实时分析. 使用Pin工具提供的INS_AddInstrumentFunction函数进行指令插桩、PIN_AddThreadStartFunction函数进行线程插桩、RTN_InsertCall函数进行敏感API插桩. 指令插桩主要分析call指令和ret指令,并结合线程插桩,获取应用程序线程创建的相关信息为每个线程构建影子栈;敏感API插桩主要分析程序异常处理过程中用到的函数并获取其参数. 此外,使用Pin工具提供丰富的API,可为动态检测模块提供应用程序运行过程中任意时刻的上下文信息,如寄存器状态、内存数据等.

动态检测模块根据动态信息提取模块提供的程序运行时信息,实现本文提出的控制流劫持攻击检测方法中的栈执行检测方法、ROP攻击检测方法和SEH异常检测方法.我们通过对3种程序异常行为的检测实现对控制流劫持类攻击的检测,检测到攻击的同时,保存漏洞攻击的细节,用于后续分析.

5 实验与分析

我们将用真实的漏洞攻击样本对系统的功能和性能进行测试,表1为具体的实验环境配置.

表1 实验环境配置

5.1 功能测试

为了验证CFHADS系统的攻击检测效果,选取了26个真实漏洞进行功能测试,这些漏洞都是针对的常用应用程序,包括Microsoft office word、Microsoft office Excel、Foxit Reader、Adobe Acrobat Reader、IE等.漏洞利用样本主要来源于exploit-db和metasploit. 具体检测结果如表2所示.

CVE-2012-0158是针对常用软件Microsoft office word 2007的经典漏洞,该漏洞利用未开启ASLR保护的msxml5.dll中跳板指令绕过DEP的安全防护,使用了经典的跳板指令jmp esp控制应用程序在栈空间中执行恶意代码. 该漏洞实际的利用方式是ret-to-libc,CFHADS虽然没有检查ret-to-libc中最开始的异常跳转,但是准确检测到控制流劫持攻击的后续异常行为. 表2的检测结果显示,EDB-ID-42918和CVE-2018-7886采用了与CVE-2012-0158相似的利用方式.

表2 真实漏洞攻击检测结果

CVE-2010-1797是针对PDF阅读器Foxit Reader的漏洞攻击,该漏洞采取了SEH利用的方式,CFHADS的检测结果为内存访问异常+SEH利用+栈执行,完整地记录了漏洞攻击从触发内存漏洞、劫持程序控制流到最后执行恶意代码的异常行为. 由于实际的系统环境与漏洞攻击的目标环境存在差异,因此检测结果中以内存访问异常居多. CVE-2010-2883采用的攻击方式为Heap Spray+ROP,但是漏洞利用失败,应用程序icucnv36.dll偏移0x2a715处访问无效内存地址0x0导致崩溃退出. 虽然漏洞攻击没有完整实施后续的ROP攻击,CFHADS仍准确地检测到漏洞攻击造成的程序异常.

实验结果表明,CFHADS能检测到控制流劫持攻击各个环节的程序异常行为,虽然主要是检测栈执行、ROP攻击和SEH利用,但是也间接防御了ret-to-libc、堆利用等攻击,除了检测到完整的控制流劫持攻击,也能检测到漏洞利用失败的控制流劫持攻击.

5.2 性能测试

通过Windows系统下常用的5个应用程序测试CFHADS对应用程序的性能影响,图7展示了应用程序在没有附加Pin、附加原生Pin、附加CFHADS情况下的应用程序内存占用情况.

从图7可以看出,Pin的运行开销约为原程序的3倍,而CFHADS的运行开销约为Pin的1.2倍. 因此,相对于基于虚拟机实现的漏洞攻击检测系统,CFHADS可以直接部署到实际应用环境中进行实时的控制流劫持攻击检测.

图7 原程序、Pin、CFHADS内存占用对比

本文提出了一种基于动态分析的控制流劫持攻击检测方法,在不依赖静态分析或者预处理的情况下检测应用程序运行时的控制流劫持攻击. 通过对控制流劫持攻击整个流程的详细分析,总结控制流劫持攻击在实际环境中造成的各种异常及行为特征,识别应用程序中的异常行为并判定为攻击. 本文基于动态分析技术实现了控制流劫持攻击检测系统,通过真实的漏洞攻击检测实验,表明该系统能够准确检测到控制流劫持攻击,良好的运行开销使得该系统能够部署到实际的应用环境中.

考虑到简单的ret-to-libc难以达到攻击目的、JOP在实际漏洞利用中实现困难以及直接将控制流转移到堆空间中执行恶意代码实现复杂等情况,本文提出的方法没有针对以上攻击方式的具体检测手段,因此在遇见这些情况时可能会产生漏报. 另外,由于Linux系统与Windows系统的一些运行机制及处理机制的不同,本文提出的方法目前只适用于Windows系统. 后续研究计划中将进一步优化检测方法,提高控制流劫持攻击检测的全面性.

猜你喜欢

漏洞指令应用程序
漏洞
《单一形状固定循环指令G90车外圆仿真》教案设计
删除Win10中自带的应用程序
新机研制中总装装配指令策划研究
关于ARM+FPGA组建PLC高速指令控制器的研究
谷歌禁止加密货币应用程序
侦探推理游戏(二)
漏洞在哪儿
三星电子将开设应用程序下载商店
太空第一人