SCI期刊 | 网站地图 周一至周日 8:00-22:30
你的位置:首页 >  冶金工业论文 » 正文

关于非控制数据攻击的防御方法探讨

2021-4-9 | 冶金工业论文

一、相关防御方法

针对非控制数据攻击,目前存在一些防御方式。其中大部分都是静态方法,需要程序源代码进行重新编译,无法应用于商业软件。也有一些动态分析解决方案,但是存在较严重的误报漏报。文献[9]提出了C语言的一个扩展语义——YARRA,通过将程序中的关键数据声明为一种特殊类型,只有类型匹配的指针才能访问这类数据。实现了一个编译器的原型,编译后的程序可以有效地防御非控制数据攻击。ValueGuard在程序数据前添加哨兵位,将原始数据和哨兵位数据包装为结构体,每次运行时检查该哨兵位。这种方式同样需要对源程序进行重新编译。数据空间随机化DSR[11][DataSpaceRandomization]将内存中数据的存储内容随机化,针对不同的变量使用不同的掩码,和实际数值进行异或操作,当读取的时候再使用该掩码异或操作获取实际数值。攻击者通过覆写关键数据进行攻击时,由于不同变量掩码不同,因此实际写入的将会是垃圾数据,无法实施攻击。文献[12]针对非控制数据攻击多数都存在非法指针解引用的现象,设计了一种基于边界检查的防御方法,但是文献[3][15]指出这存在很严重的误报和漏报。文献[13]通过在硬件层面给寄存器、内存添加标记位,这样可以高效地进行污点标记,不过这需要全新的硬件支持,实用性不强。

二、防御原理

基础的动态污点分析(DTA)针对控制数据攻击非常有效,但是无法防御非控制数据攻击。研究发现,控制数据攻击和大部分非控制数据攻击都具备相同的特征,向攻击者构造的地址写入数据,或者读取攻击者构造的地址的数据。概括地说,大部分攻击都依赖于一个不安全的指针解引用[12][13],而这个不安全的指针通常是由攻击者构造的。例如格式化串攻击中,常见的攻击方式是攻击者往自己精心构造的地址写入一个数值,这就存在不安全指针的解引用。Chenet.al[2]提到的针对HTTPserver-GHTTPD和WU-FTPD的攻击实例,也是通过覆写指针,指针解引用后实施攻击。根据这一特征,我们提出了指针污点分析方法,它是DTA的一种扩展,因此我们这一方法也分为三个步骤:taintsource(标记污点来源);taintpropagation(传递污染属性);taintsink(污点信息终点)。污点来源source就是来自外部的数据,可以是读取自文件、网络等;根据二进制指令的实际含义定义不同的传播规则(即propagation);sink是污点数据的到达处,通常会在此处设置安全规则检查。下面我们定义两个重要的概念。定义1污点标记(tainttag,T-tag)是内存数据的一个属性,表示该数据是否是来自外部、受污染的。真值表示是受污染的,假值表示不是受污染的。定义2指针标记(pointertag,P-tag)是内存数据的一个属性,表示该数据是否是合法指针,是否可以用作地址。真值表示是合法指针,假值表示是非法指针。我们的防御方法就是围绕内存数据的这两个属性的标记、传播和检查。

1.标记污点来源

针对T-tag,我们监控程序读取文件、网络数据等行为,将获取的数据初始化标记为受污染的,其他数据标记为非污染的。针对P-tag,我们需要识别出该内存数据是否是合法的地址。有两种方式产生的数据可以用作指针,分别是动态分配空间的指针和静态分配空间的指针。初始状态下,只有通过这些方式产生的数据,才认为是合法的指针,其他数据默认会标记为非法指针。

2.传递污染属性

数据作为不同指令类型操作数时,其传播规则也不同。表1概括了不同的传播策略。我们将指令主要分为算术运算指令、逻辑运算指令、数据传输指令和特殊指令,下面针对T-tag和P-tag分别进行详细描述。

(1)T-tag传播策略

算术运算指令:add,sub,mul等Example:mulop1,op2Rule:T(op1)=T(op1)∨T(op2)解析:只要两个操作数中任一个为受污染的,则污染属性传播到目标操作数中。数据传输指令:mov型指令,包括mov、movsb等Example:movop1,op2Rule:T(op1)=T(op2)解析:源操作数的污染属性直接传播到目标操作数中。逻辑运算指令:and,or,shl等Example:andop1,op2Rule:T(op1)=T(op1)∨T(op2)解析:只要两个操作数中任一个为受污染的,则污染属性传播到目标操作数中。特殊指令:xor,test等Example:xorop1,op1Rule:T(op1)=0解析:该指令的目的是将相应寄存器中的数据清空,因此污染属性将会清除。

(2)P-tag传播策略

算术指令(相加、相减):add,subExample:addop1,op2Rule:P(op1)=P(op1)⊕P(op2)解析:两个操作数都是合法指针,或者都不是合法指针,则目标操作数不是一个合法指针。这个很容易理解,两个地址之间加减,其结果是两者的相对偏移,所以不是一个合法的地址。如果两个操作数只有一个是合法指针,则这是一次通过基地址和偏移量计算地址的操作,其结果还是一个合法指针。算术指令(相乘等其他指令):mul,div等Example:mulop1,op2Rule:P(op1)=0解析:不是正常的地址计算操作,因此其结果都标记为非法指针。逻辑运算指令(取基地址的AND指令):andExample:andop1,0x11..00Rule:P(op1)=P(op1)解析:这是一条比较特殊的and指令,目的是获取源操作数的基地址,因此其结果的P-tag属性和源操作数的P-tag属性相同。逻辑运算指令(其他指令):or,not等Example:orop1,op2Rule:P(op1)=0解析:不是正常的地址计算操作,因此其结果都标记为非法指针。数据传输指令:mov型指令,包括mov、movsb等Example:movop1,op2Rule:P(op1)=P(op2)解析:源操作数的污染属性直接传播到目标操作数中。

3.攻击判定

攻击判定分为两类,一类是常见的控制数据攻击,监控跳转类指令(Jump、Call、Ret等),当其操作数的T-tag属性为真,即是来自外部的污点数据,表明这是一次攻击。第二类是监控指针的解引用:如果T-tag属性为假,即不是来自外部的污点数据,则不管P-tag的属性值,指针的解引用都是合法的;如果T-tag为真并且P-tag为假,即当来自外部的污点数据,并且不是一个合法指针,被解引用时,则表明这是一次攻击;如果T-tag为真并且P-tag也为真,虽然是来自外部的数据组成的地址,但是合法指针,所以可以解引用,这也很好地解决了之前防御方法存在的漏报误报问题[3][15]。表2定义了攻击判定的规则。

三、系统具体实现

本系统是在UbuntuLinux下基于动态二进制分析框架Pin开发的指针污点分析工具DynamicPointerTaintAnalysisTool,简称DPTA。Pin可以在可执行二进制代码中插入一些探测函数,用于观察、记录、分析等。通过Pin提供的API可以编写各种分析工具,这样程序运行完以后,统计和分析结果也同时产生。DPTA除了具有基本的DTA功能以外,主要着眼于指针污点分析,因此具有防御控制数据攻击和非控制数据攻击的能力。图2是DPTA的系统框架。系统会监控系统调用,将来自外部的数据标记T-tag和P-tag属性,并存储到Tagmap中。应用程序的每条指令通过Pin进行翻译后执行,同时DPTA会插入一些分析代码,实时监控程序运行状态。程序执行过程中会动态更新Tagmap,并在安全敏感处执行检查,发现攻击时触发警报。

Tagmap的设计Tagmap,又被称为影子内存,是在系统中开辟的一块新区域,用来存储程序内存数据的标记信息。在本系统中,我们使用两个bit位来标识每一块内存的T-tag和P-tag属性,分别为T-bit和P-bit。T-bit为0表明不是污点数据,1表示是污点数据。P-bit为0表示不是一个合法指针,1表示是一个合法指针。Tagmap中标记的地址和实际的数据存储地址有一对映射关系,可以通过计算来获取。程序初始运行时,Tagmap会根据实际情况初始化为不同的数值,默认下这两个bit位都是置为0。T-bit的初始化和传统的DTA相同,将read、recv等函数获取的数据标识为1(污点数据)。P-bit的初始化相对复杂性,主要是指针的产生可能会有很多种情况,因此指针识别是很重要的一环,下文我们会对其进行详述。识别出的指针,其P-bit将会被标识为1(合法指针)。

1.指针识别

指针识别是本系统中非常重要的一部分,但是二进制中的指针识别向来是一件非常困难的事情。我们将指针区分为两类,一类是指向动态分配空间的指针,另一类是指向静态分配空间的指针,例如全局变量的地址。图3展示了内存的布局,动态区域主要是堆和栈,静态区域包括静态数据区、代码区、动态链接库的静态数据区和代码区。下面分别对这两类指针的识别进行阐述。

(1)动态分配的堆空间指针

动态分配的空间一般需要调用一些系统调用,如mmap、brk、mmap2、mremap、shmat等。因此可以监控这一类系统调用,其返回的指针就是合法的堆空间指针。例如增加对系统调用brk的监视,根据Pin的api,我们给brk绑定一个监控函数post_brk_hook:当产生系统调用brk时,监控函数中会将返回的指针的P-bit设置为1,表明是合法的指针。同理也可以添加对其它系统调用的监听。栈空间的指针都是来自于栈指针(StackPointer),因此我们将程序开始时候的栈指针的P-bit设为1。

(2)静态分配空间的指针

静态分配空间的指针识别比较复杂。当程序被编译成重定向目标文件时,所有静态分配空间的引用都会放置在重定向表中。如果应用程序中有着完整的重定向表,我们可以精确地识别出所有静态的指针初始化。然而大部分情况下都缺少这些信息,因此对于这种情况,我们需要其他方法来识别指针。DPTA是基于x86指令集下的Pin开发的,通过反编译程序可知,这类指针初始化具有一个特征,都是通过类似movl的指令,将一个32-bit的常数赋值给寄存器,据此我们可以保守地识别出x86下的静态分配空间指针。我们首先获得静态空间的起始地址和终止地址,然后在DPTA插桩的时候检查movl类的指令,如果其操作数是立即数和寄存器,并且立即数在静态空间的地址范围内,则认为其是合法的指针初始化。这些操作虽然比较复杂,但是这是插桩代码,因此其对效率影响有限。

2.污染属性传播和攻击判定

污染属性的传播也就是在程序运行中,每块内存数据所对应的两个bit位的变化。按照上文提到的传播策略,当程序运行时,Tagmap中的数据将按照表1中的策略进行更新。攻击判定,首先针对跳转类指令(Jump、Call、Ret等),需要进行判断,这和传统的DTA相同,此处不做详述。针对指针解引用的判断,根据指针解引用指令(如mov指令)的操作数,如果源操作数是指针,T-bit为1并且其P-bit为0,表明要读取一个非法指针指向的内存区域数据,判断这是一次对非法指针的解引用,是一次攻击。如果目的操作数是指针,T-bit为1并且其P-bit为0,表明将对一个非法指针指向的内存区域写入数据,判断其为攻击。表3是一段攻击判定的示例代码。其中alert_mov方法将会按照我们定义的策略对该内存地址的T-bit和P-bit进行检查,判断是否是一次攻击。

四、实验评估

在UbuntuLinux下对DPTA进行实验评估,内核版本是3.4,运行的平台为CPU2.67GHz,内存4GB。实验一方面验证该工具是否能够检测出非控制数据攻击和控制数据攻击,另一方面测试工具对应用程序效率的影响。

1.攻击检测验证

我们选取了具有代表性的四个控制数据攻击和四个非控制数据攻击,进行了多次测试。表4的测试结果表明DPTA针对控制数据攻击和大部分非控制数据攻击都具有良好的防御能力,但是对于不通过指针修改关键数据的攻击,我们还无法防御,这是我们系统的局限性。

2.性能测试

我们选取了5个程序来测试我们系统的性能损耗,同时我们使用了Kemerlis开发的DTA工具Libdft[16]进行参照,表5给出了最终的测试结果。总体而言,系统的损耗从1.5x到28.0x不等,平均性能损耗是12.5x,这与Memcheck的运行负载相近。相比于Libdft,DPTA的系统负载比较高,这是因为我们采取了比较严格的监测策略,除了监控跳转指令,还包括了非常常见的数据传送指令(mov等),这会给系统增加非常大的运行开销。但是我们系统可以防御大部分的非控制数据攻击,而Libdft没有这一能力。

五、结束语

本文在动态污点分析的基础上,针对非控制数据攻击提出了一个改进的指针污点分析方法,通过跟踪内存数据的污点标记和指针标记,监控是否存在非法的指针解引用。实现了原型工具DPTA,实验评估表明,该工具可以防御控制数据攻击和大部分非控制数据攻击。虽然DPTA实现了我们的防御模型,但是还存在一些问题需要我们进一步研究:(1)实验表明我们的原型系统运行效率并不是很理想,距离商业化应用还有距离。我们计划通过两方面进行优化:一方面优化Tagmap的数据结构,更新Tagmap信息是系统中常见的操作,因此快速获取Tagmap中的信息会对效率产生很大影响;另一方面手动分析程序调用的常用函数的语义信息,获取其是否涉及污点传播,对于不涉及污点传播的函数不进行插桩分析。(2)目前采取的指针识别方法并不是很准确,尤其是静态分配空间的指针,下一步计划分析识别失败的指针,归纳其特征,提高指针识别的准确率。(3)本系统无法检测出不通过覆写指针实施的非控制数据攻击,可以通过结合静态分析的方法防御,但是这不是我们下一步的主要方向。(本文图、表略)

本文作者:刘小龙 郑滔 单位:计算机软件新技术国家重点实验室(南京大学)  南京大学软件学院

Top