2. 南京大学 计算机科学与技术系, 江苏 南京 210023
2. Department of Computer Science and Technology, Nanjing University, Nanjing 210023, China
整型(integer type)是C/C++语言中常用的基本数据类型,广泛应用于整数数值的表示、算术运算、内存地址、数组下标、循环计数以及标志位[1].为了满足不同的计算需求,C/C++语言提供多种字节长度的整数类型,根据具体的体系结构、编译环境和语言标准来解释整数的符号、宽度及运算规则.
计算机中采用有限字节来表示整数,意味着整型变量的取值是有严格范围的.对于由N比特表示的无符号类型,其表示范围是0~2N-1;由N比特表示的有符号整型,其表示范围则是-2N-1~2N-1-1.因此,算术运算如加法、减法、乘法和左移操作可能使运算结果超出相应类型的表示范围的上界或者下界,使得计算结果是期望值与相应类型极值的取模,这类计算结果的失真称为整数溢出.例如,32位乘法0x40000001*4的运算结果并不是0x100000004,而是4.超出上界称为整数上溢(integer overflow,简称OF),超出下界称为整数下溢(integer underflow,简称UF).
程序中的类型转换操作会涉及不同符号和宽度的转换.符号上的转换会引起无符号类型的最高位与有符号类型的符号位之间的转换,可能引起数值上的误解.一个有符号类型的负数数值会被解释成一个很大的无符号类型的正数数值,反之亦然.例如,有符号的-1会被解读为最大的无符号正数232-1.这类数值上的误解在内存空间分配或者安全条件判断上会造成严重的后果,称为符号错误(signedness error,简称Sign Err). C/C++语言设计不同宽度的整数类型,包括char,short,int,long和long long.高宽度的整数类型转换成低宽度的整数类型,可能导致高宽度的整数类型在高位上的缺失,使转换前后的数值大小不等,引起截断错误(truncation error,简称Trunc Err).例如,32位int类型存放的65540(即0x10004)如果用16位short类型存放,数值则会转换为4.
如果算术运算引起的计算结果失真,或者类型转换造成的数值被误解,使程序语义偏离了程序员的期望,则称该整数操作发生了整数缺陷(integer-based weakness),它们易被攻击者间接利用,实施诸如恶意代码执行、拒绝服务(denial of service)等攻击行为.国际权威漏洞披露组织CVE(common vulnerabilities and exposures)[2]在2007年发布的年度报告中指出,整数漏洞(integer-based vulnerability)**已成为威胁软件安全的第二大类漏洞[4],仅次于缓冲区溢出漏洞.目前,很多研究者致力于全面、有效、精确地检测程序中潜在的整数漏洞,代表性的工作如RICH[5],IntPatch[6],IntScope[7],BRICK[8],RA[9]和Kint[10]等.本文统计了CVE公布的历年整数漏洞数量,如图 1所示.其中,横坐标表示年份,纵坐标表示漏洞数量.
为了更好地理解整数漏洞问题,全面认识当前的研究现状,进一步完善检测方法,本文综述了整数漏洞的研究进展.第1节从缺陷发生后行为(behavior after weakness)的角度提出新的整数漏洞的安全模型(security model).第2节分类讨论现有的检测方法.第3节通过对现实整数漏洞的实例研究,分析其特征及分布.第4节提出整数漏洞问题中存在的挑战和有待研究的问题.
可以看出:整数漏洞自2007年开始得到一定的缓解,漏洞数量大致呈现逐年下降的趋势.可能的原因是CVE等发布的漏洞报告引起了人们对整数操作代码安全的重视以及整数漏洞检测研究等工作的作用.然而漏洞数量仍然居高不下,究其原因包括:
1) 整数操作在程序中普遍存在,但只有其中极少一部分可能引发程序安全问题,程序员难免会遗漏对部分整数操作的数值范围的安全检查(如观察4指出,Not Realize是引入整数漏洞的主要原因).
2) 程序员对复杂整数语义(integer semantics)理解不充分[10],导致对已知整数漏洞的修复仍不安全(如第1.3.3节讨论).
3) 程序员会故意使用整数溢出(intentional uses of integer overflow)[11]以达到编程目的,如随机数生成(random number generation)和哈希值计算(hash value computation)等.产生的异常数值仍然在程序员的期望内,属于良性(benign)的溢出.程序员对故意使用溢出的容忍,为精确识别整数漏洞提出挑战(如第1.3.4节讨论).
1 整数漏洞安全模型 1.1 整数缺陷本文将整数缺陷表示成一个由整数操作op、操作数类型符号信息sign、操作数类型宽度信息width和操作数数值范围信息range组成的四元组:
|
其中,INT_OP是程序中可能引发整数缺陷的操作***,包括加法ADD、减法SUB、乘法MUL、左移SHL、符号类型转换SIGN_CAST和宽度类型转换DOWN_CAST.sign描述了INT_OP的源操作数和目的操作数的类型符号信息对,SIGN包括有符号类型signed和无符号类型unsigned两类.width描述了INT_OP的源操作数和目的操作数的类型宽度信息对,WIDTH用int_8,int_16,int_32和int_64来表示.TRIGGER_COND指源操作数在当前(op,sign,width)下触发整数缺陷的数值条件(可触发整数缺陷的数值条件,是判定整数漏洞的基本.细节可参阅文献[5]的表 1和文献[12]的表 2).以32位无符号加法x=o1+o2为例,该操作发生整数溢出的触发条件是:操作数o1和o2相加后的理论结果大于32位无符号整型的表示上界,即232-1.
定义1(整数缺陷的判定). 程序中的整数操作(op,sign,width)导致整数缺陷,当且仅当源操作数的取值范围满足缺陷触发条件,即rangeÎTRIGGER_COND.
1.2 基于缺陷发生后行为的整数漏洞安全模型沿用RICH[5]的分类,整数缺陷可分为整数上溢、整数下溢、符号错误和截断错误(可参阅文献[5]图 1的现实漏洞实例).加法、减法、乘法和左移操作导致的整数溢出和类型转换操作导致的截断错误会使计算结果与期望值存在偏差,类型转换操作导致的符号错误会混淆负数和极大正数之间的数值解读.我们称这些受整数缺陷影响的数值为异常整数数值(malformed integer value).整数缺陷的直接危害是计算结果失真、数据丢失和数值被误解,并不会直接对内存作越界修改,所以通常不能直接利用整数缺陷实施攻击.然而,攻击者可以利用程序中使用异常整数数值的敏感操作(security-related operation)间接地实施恶意攻击,危害程序的安全性[5, 12].
传统的整数漏洞安全模型[5, 8, 9, 11]与整数缺陷模型类似,仅从操作类别、符号信息、类型信息和操作数取值范围的角度来判断整数操作是否引发漏洞.文献[6, 7, 12]扩展了传统的安全模型,将既能被用户输入控制又能被程序敏感操作使用的整数操作作为整数缺陷的判定对象.然而,程序中的异常整数数值还可能被程序员添加的安全检查语句过滤[6, 10, 13],而当前的安全模型并没有考虑这一要素.为此,本文从整数缺陷发生后行为的角度出发,提出更全面的整数漏洞安全模型,以完善对整数漏洞的描述.
本文定义了基于缺陷发生后行为的整数漏洞安全模型,即,一个由整数缺陷INT_WEAK、数值是否可信TRUST、安全检查SANITY_CHK和使用模式USE_PATTERN组成的四元组:
INT_VULN:áINT_WEAK,TRUST,SANITY_CHK,USE_PATTERNñ|TRUST,SANITY_CHKÎBoolean
USE_PATTERNÎ{NONE,MEM,ARRAY,WHILE,IF,PTR}
其中,TRUST标识源操作数是否由程序外部通过用户输入得到,因为对于用户不能控制的整数缺陷,攻击者是无法利用的[6, 12].SANITY_CHK和USE_PATTERN是整数缺陷发生后的具体行为,SANITY_CHK表示程序员针对可能的异常整数添加的数值过滤,如果能捕获到异常整数数值则为true,否则为false.USE_PATTERN指异常整数数值在程序中的使用模式,包括NONE(表示异常整数数值没有被使用,或者仅被用于与程序安全性无关的使用点[11])、MEM(与程序内存操作相关的敏感操作)、ARRAY(用于数组访问操作)、WHILE(用于循环判断语句)、IF(用于程序安全条件判断语句)和PTR(用于指针偏移计算操作).
基于缺陷发生后行为的整数漏洞安全模型不再简单地将整数缺陷判定为整数漏洞,既考虑该缺陷是否可能会被攻击者利用,又考虑了异常整数数值是否会被程序员的安全检查代码捕获、是否会被程序安全相关的敏感操作使用.因此,整数漏洞的判定过程可定义如下:
定义2(整数漏洞的判定). 程序中的整数操作(op,sign,width)导致潜在的整数漏洞,当且仅当:
rangeÎTRIGGER_CONDÙTRUST=falseÙSANITY_CHK=falseÙUSE_PATTERN!=NONE.
由此可见,一个整数操作满足以下4个充分条件即可判定为整数漏洞:
· T1:源操作数必须来自不可信数据,即能被攻击者的输入控制.
· T2:源操作数的数值范围range满足缺陷触发条件TRIGGER_COND,即引发整数缺陷,产生的目的操作数为异常整数数值.
· T3:异常整数数值在随后的使用中,能绕过程序员实现的不严密的安全检查语句SANITY_CHK,或者随后的使用中没有安全检查语句.
· T4:异常整数数值必须用于可影响程序安全性的敏感操作,才能被攻击者利用,以实施恶意攻击.
1.2.1 使用模式USE_PATTERN定义3(不严重的整数缺陷uncritical INT_WEAK). 程序中的整数操作(op,sign,width)导致不严重的整数缺陷,当且仅当rangeÎTRIGGER_CONDÙUSE_PATTERN=NONE.
不严重的整数缺陷产生的异常整数数值不会流入与程序安全性相关的敏感操作中(不满足充分条件T4),因此不会被攻击者利用完成恶意攻击,在现实的整数漏洞检测中需要排除对这类缺陷的报告.例如,SPEC 2000[14] 164.gzip中,deflate.c:540处的无符号减法产生的异常数值在随后并没有被使用;186.crafty中,iterate.c: 438处的有符号乘法产生的异常数值只是用于调试信息的打印.
按照敏感操作的类别,本文将异常整数数值的使用模式分为以下5类:
1) MEM使用模式:通过影响与程序安全性相关的库函数如malloc(×),memcpy(×),strncpy(×),memset(×)等,影响内存空间的分配、内存或字符串的复制,完成诸如缓冲区溢出、恶意代码执行、拒绝服务等攻击,是最为常见的异常数值使用模式,如实例:
CVE-2008-1722[15],CVE-2011-1659[16],CVE-2011-0188[17].
2) ARRAY使用模式:程序中整数的一个重要用途是数组的下标.ARRAY使用模式借助实际值与期望值的偏差,完成数组越界访问攻击,如实例CVE-2012-4405[18].
3) WHILE使用模式:常常借助异常整数数值来影响循环判定条件,进而影响循环次数,造成无限循环(infinite loop)的攻击,如实例CVE-2010-4164[19].
4) IF使用模式:整数可以用于判断程序中的运行状态,条件判断语句根据整数数值来决定控制流的走向.攻击者利用异常数值与期望值的偏差或数值的误解,使程序执行错误的程序行为,如实例:
CVE-2009-1438[20].
5) PTR利用模式:借助异常数值与期望值的偏差,来影响指针偏移运算中的偏移值,从而完成指针越界访问攻击,如实例CVE-2010-2500[21].
1.2.2 安全检查SANITY_CHK防止整数漏洞的一种有效方法是阻止异常整数数值流入程序的敏感操作点,因此,经验丰富的程序员会预期整数缺陷的发生,选择对重要的整数操作(可能的整数缺陷发生点)添加数值范围的安全检查[6, 10, 13],以捕获异常数据.
定义4(被拒绝的整数缺陷denied INT_WEAK). 程序中的整数操作(op,sign,width)导致被拒绝的整数缺陷,当且仅当rangeÎTRIGGER_CONDÙSANITY_CHK=true.
图 2(a)描述了一个被拒绝的整数缺陷的代码实例,是针对CUPS的CVE-2008-1722[15]漏洞的修复.在原始的漏洞代码中,攻击者可以恶意构造一个拥有很大width和height的PNG图片文件,引发第10行的整数乘法操作溢出,然后导致第16行分配的内存空间比预期少,造成缓冲区溢出.第11行~第15行的安全检查语句是开发者针对该漏洞添加的修复代码.显然,异常整数数值bufsize会被第11行的安全检查语句捕获,不会到达第16行的敏感操作,该整数溢出为被拒绝的整数缺陷.
被拒绝的整数缺陷因不满足整数漏洞判定条件中的T3,不会流入与程序安全性相关的敏感操作中,进而不会被攻击者用来完成恶意攻击.因此,在整数漏洞检测中,需要排除对这类缺陷的报告.
1.3 影响因素体系结构、编译器和程序员是影响整数漏洞的重要因素,这些因素不易通过整数漏洞安全模型表示,常常被人们忽视,但却给整数漏洞的检测带来极大的挑战.
1.3.1 体系结构体系结构决定了整数的表示宽度.在不同的体系结构下,用于表示整数的位数不同,会影响整数缺陷模型中的宽度信息width和触发缺陷的取值范围TRIGGER_COND,进而影响整数缺陷的判定.相同的程序代码移植到不同的体系结构,可能会发生整数漏洞,而人们往往会忽略体系结构带来的影响.
图 2(b)描述了Apache-1.3.42中由体系结构变更导致的截断错误实例CVE-2010-0010[22].在32位体系结构下,int类型和long类型都是由32比特表示,然而在64位体系结构下,long类型由64比特表示.该软件在32位体系结构下运行正常,但在64位体系结构下存在截断错误.具体来说,long类型的remaining变量在第11行通过socket从外界读取数值,随后在第17行强制转换成int类型后被ap_bread(×)调用,攻击者可以通过构造恶意长度的buf来实现第17行的截断错误.
1.3.2 编译器的过度优化(over optimization)发生后验证(post-condition test)[11]是比较常用的安全检查.在整数操作之后添加对目的操作数的数值范围的检查,以判断是否发生了整数缺陷.例如,为保证无符号加法c=a+b不受整数溢出的影响,程序员在该加法之后添加if (c<a)的检查代码.然而在编译器的优化过程中,c<a会被表示为a+b<a,对于无符号的整数运算规则,该条件永远为false.在高优化级别下,此类安全检查代码会被编译器视为死代码(dead code)而自动删除掉[13],从而使程序员实现的安全检查机制失效,即,被拒绝的整数缺陷转变成潜在的整数漏洞.
1.3.3 程序员对整数操作语义的理解不准确由于对复杂的语言标准和整数操作语义的理解不准确,程序员在对已知整数漏洞的修复中出现修复不完备或引入新漏洞的问题,造成检查代码失效,如Wang等人[10]的讨论,其主要原因是使用了不正确的限制边界(incorrect bounds)、不正确的检查格式(malformed checks)、符号的误用(incorrect sign)以及引入undefined behavior[13, 23].
1.3.4 整数溢出的故意使用程序员会故意使用整数溢出来实现特定的功能,例如随机数生成、哈希值计算、消息的加密等[11].这些整数溢出是程序员所容忍的,其运算结果也在程序员的期望之内,属于良性的整数溢出,因此在整数漏洞检测中需要排除对故意使用的报告.
2 检测方法分析由基于缺陷发生后行为的整数漏洞安全模型可知,T1~T4是判定整数漏洞的充分条件,研究者通过识别满足其中一个或多个充分条件的整数操作来判定潜在的整数漏洞.一个整数操作满足的充分条件越多,则其成为整数漏洞的可能性越高.本文从漏洞判定规则对4个充分条件的满足情况出发,将当前的检测方法大致分为以下3类:
1) 整数缺陷的识别weakness_detect:通过判定源操作数的值范围range是否满足整数缺陷的触发条件TRIGGER_COND来判定整数漏洞,即,将所有的整数缺陷都判定为整数漏洞.漏洞判定规则可描述为Vul-R1:T2®INT_VULN.在实现上,分为由代码替换(如SafeInt[24],IntSafe[25])或代码插装(如RICH[5], IOC[11])实现的动态判定以及静态的约束求解(如RA[9]).
2) 危险路径上整数缺陷的识别path_weakness_detect:提取程序中由不可信输入点到敏感操作点之间的所有执行路径,随后判定执行路径上的整数操作是否会发生整数缺陷,包括Kint[10],IntPatch[6], IntScope[7],SmartFuzz[26],DRIVER[12]等.漏洞判定规则可描述为Vul-R2:T1ÙT2ÙT4®INT_VULN.
3) 危险路径上敏感操作点使用异常整数数值的识别sink_malform_use:提取整数缺陷发生点到敏感操作点的执行路径,排除安全检查语句对异常整数数值的过滤,将敏感操作能使用异常整数数值作为整数漏洞的判定依据,如SIFT[27].漏洞判定规则可描述为Vul-R3:T1ÙT2ÙT3ÙT4®INT_VULN.
2.1 整数缺陷的识别weakness_detect由定义1可知,源操作数的数值范围range是否满足触发条件TRIGGER_COND是判定整数缺陷的充分条件.数值范围range最直观地可以在程序运行时动态得到,也可以在静态阶段得到粗略估算,因此,weakness_ detect方法又可分为动态和静态两类.
2.1.1 动态weakness_detect源操作数的具体数值在程序运行时是确定的,因此,对整数操作添加触发条件的判定是检测整数缺陷的有效方法.触发条件判定语句的添加可以分为代码替换(code transformation)和代码插装(code instrumentation).
代码替换方法一般在源代码上将整数操作直接替换为安全的整数操作库函数,包括SafeInt[24],IntSafe[25], IntegerLib[28, 29]和Ranged Integer[30].例如,有符号加法操作xsi+ysi会被替换为addsi(xsi,ysi),函数addsi实现了对操作数的数值范围的判断.这样,代码的可读性虽然受到影响,但其安全性得到加强.然而,代码替换方法的不足之处是安全库函数本身可能引入新的整数漏洞,如IOC[11]从IntegerLib中检测出20个整数溢出错误.
代码插装方法一般借助编译器如GCC和LLVM,在中间表示层IR(intermediate representation)插装对数值范围的判断,不会修改源代码,例如ARCHERR[31],RICH[4],AIR[32],IOC[10],BRICK[7]和RICF[33].表 1是对基于代码插装的动态weakness_detect方法的介绍,表中第1列表示所属的参考文献编号;第2列表示该文献的发表年份;第3列表示原型工具;第4列表示该方法适用的分析对象类别,包括源代码和二进制代码;第5列表示该方法能处理的整数漏洞类别;第6列表示该方法产生的动态运行开销;第7列描述该方法的特点.其中,ARCHERR考虑了体系结构对整数漏洞的影响(如第1.3.1节讨论),为整数算术运算插装对应体系结构的判定代码.RICH将类型安全语言中的子类型理论(sub-type theory)应用到C语言中,为整数操作语义定义形式化的安全规则,根据类型规则约束插装动态验证代码,插装后的代码仅有5%的运行开销.BRICK是第一个检测二进制整数漏洞的分析工具,但会产生50倍的运行开销.IOC从软件工程的角度出发,深入探讨了整数溢出的特征(是否为程序员故意使用,是否属于undefined behaviors).
2.1.2 静态weakness_detect整型变量在程序中的取值范围可以在静态阶段得到粗略估算.具体方法是:根据条件判断语句约束变量在不同分支下的数值范围,在遍历抽象语法树的过程中不断更新深层分支下的约束信息,从而得到变量的大致取值范围.利用这些粗略的取值范围信息来判定是否满足触发条件TRIGGER_COND,包括文献[34, 35].然而,静态得到的数值范围比较粗糙,会产生很多的误报.
RA[1]提出了新的值范围分析算法,以更精确、快速地求解变量的值范围,工作包括:1) 按拓扑顺序分析强连通分支(strong connected component),以加快约束求解的速度;2) 提出分阶段的方法来提取变量之间关系操作(comparison between variables)的约束;3) 设计新的中间表示形式,以加快值范围的sparse analysis.实验结果表明:RA能够在10s内处理百万行的代码规模,能够静态判定25%的整数操作是安全的,即,取值范围不满足触发条件的整数操作.
2.2 危险路径上整数缺陷的识别path_weakness_detect定义5(危险路径critical path). 由不可信输入到敏感操作的执行路径称为危险路径.
危险路径是整数漏洞多发的程序片段,攻击者可以通过不可信输入来控制程序中的数值范围,进而在敏感操作点控制异常数值来危害程序的安全性.危险路径上的整数操作满足条件T1和T4,因此,提取程序的危险路径是识别整数漏洞的有效手段.
path_weakness_detect方法通常借助污点分析(taint analysis)、类型规约(type qualifier)等方法来提取程序中的危险路径,随后,利用代码插装或静态约束求解的weakness_detect方法来判断危险路径上的整数操作是否发生整数缺陷,将报告的缺陷判定为潜在的整数漏洞.
表 2是path_weakness_detect方法的介绍,表中第1列~第5列与表 1前5列的含义相同,第6列表示危险路径的提取方法,第7列表示危险路径中敏感操作的类别,第8列表示整数缺陷的判定方法.
IntPatch[6],Kint[10],IntScope[7]和IntHunter[36]主要检测流入MEM敏感操作的整数溢出漏洞,即IO2BO[6]漏洞.IntPatch采用类型规约的方法跟踪用户输入数据流向内存分配操作点,然后为路径上所有的整数操作插装验证代码.IntPatch能够有效地抽取危险路径上的整数操作,实验结果表明:IntPatch能够排除90%的无关整数操作,且运行开销极低,约1%.Kint处理的对象是大规模系统软件,如Linux内核,需要程序员为关键函数和变量提供注释以进行全局的数值范围求解.Kint针对Linu内核发现了100多个新的整数溢出漏洞.不足之处是:Kint因别名分析、循环展开等问题产生误报,同时也会因约束求解器的有限求解能力而产生漏报.IntScope和IntHunter的分析对象则是二进制代码,根据静态提取的数值约束信息,采用符号执行的方法判定缺陷的发生.
Pozza等人[37]和DRIVER[12]采用污点分析的方法尝试提取程序中所有危险路径,随后判定危险路径的整数操作是否会触发整数缺陷.不同点在于:Pozza等人调用GCC编译器内置的值范围分析VRP(value range propagation)来判定整数缺陷,分析精度不足,存在较高的误报率;而DRIVER采用代码插装的方式来动态判定整数缺陷,精度相对较高.
IntFinder[38]和SmartFuzz[26]分析的对象是二进制代码,只考虑不可信数据到整数操作的执行路径.其中, IntFinder是对BRICK的改进,通过扩展反汇编的类型系统,得到相对完整的类型信息,从中抽取可疑指令集作为动态保护的对象,运行开销由原来的50倍降低到5倍左右;SmartFuzz从程序入口为起点收集数值范围的约束信息,生成测试用例来触发整数缺陷,以验证程序的安全性,有较高的测试用例覆盖率.
2.3 危险路径上敏感操作使用异常数值的识别sink_malform_usesink_malform_use方法全面分析危险路径上整数缺陷的发生后行为,确保该缺陷产生的异常数值流入敏感操作点.如果异常数值被安全检查语句捕获,则不会将该整数缺陷判定为整数漏洞.该类方法的漏洞判定规则满足所有4个充分条件T1~T4,理论上是最精确的检测方法.
目前,仅有SIFT[27]属于sink_malform_use方法的范畴.与上述方法不同的是,SIFT不是一个漏洞检测工具,而是一个健全的(sound)输入过滤器(input filter),即,如果一个输入能通过其过滤模块,则该输入在程序的正常使用中不会引起整数溢出错误.与IntPatch和Kint类似,SIFT考虑的敏感操作仅仅是内存空间的分配和复制操作(MEM使用模式),即,分析对象是IO2BO漏洞.
SIFT从敏感操作点出发,进行过程间的、需求驱动的、后向的静态分析(inter-procedural,demand-driven, backward static analysis)提取所有从程序入口到敏感操作的路径上与输入域(input fields)相关的约束信息集合,该约束信息集合包含程序针对各个输入域在到达敏感操作点之前进行的所有计算.SIFT再结合对输入文件的结构分析,构造输入过滤器.对于给定的输入,SIFT根据约束集合中对相应输入域的条件限制来评估该输入是否能够触发溢出.SIFT具有以下优点:
1) 健全性(soundness):传统的过滤器生成方法以一个可触发漏洞的危险路径为起点,收集这条路径的约束信息并借助符号执行生成过滤器.传统的方法需要可触发漏洞的危险路径为输入,未被分析的路径也可能引发漏洞.而SIFT从程序中所有的敏感操作点出发,后向地提取约束信息,能够保证覆盖所有的可能流入敏感操作点的路径.
2) 高效(efficiency):传统方法将待分析路径上所有的约束都进行收集求解,而SIFT只收集路径上与输入域相关的约束,这样能够极大地提高求解效率.
3) 精度(accuracy):Kint,IntScope和SmartFuzz收集从程序入口到溢出操作之间的数值约束信息,并没有覆盖溢出操作之后可能存在的安全检查语句,因而会将被拒绝的整数缺陷判定为整数漏洞,产生误报.而SIFT从敏感操作点出发后向收集约束,包含安全检查语句.以图 2(a)中代码片段为例,SIFT从第16行的malloc函数出发后向收集约束,自然会覆盖第11行的安全检查,从而排除对该被拒绝的整数缺陷的误报,即,一个输入虽然能触发第10行的整数溢出,但SIFT并不会过滤该输入,因为第11行的安全检查能确保溢出值不会被第16行的敏感操作使用.
2.4 讨 论表 3是对这3类检测方法的小结,其中,第1列表示检测方法的名称,第2列表示漏洞判定规则所能满足的充分条件,第3列比较3类方法的检测精度,第4列介绍误报情况,第5列给出评价.从充分条件的满足情况可以看出,3类方法是递进扩展的关系.
缺陷识别weakness_detect方法是检测整数漏洞的基本工作,以充分条件T2作为判定整数漏洞的规则.这类方法的优点是不会产生漏报,但由于没有考虑危险路径和缺陷发生后的安全检查这两个条件,因此难免会产生大量的误报(误将uncritical INT_WEAK和denied INT_WEAK判定为整数漏洞),给出的缺陷报告需要人工的进一步确认.其中,动态weakness_detect方法已经得到了很好的应用,如整数操作的安全库函数被越来越多的开发者使用、代码插装工具IOC已内置于最新版本的LLVM编译器中;静态weakness_detect方法虽然分析精度不高,但被RA[9]应用于排除静态不满足缺陷触发条件的整数操作中,或者结合符号执行技术以生成可以触发整数缺陷的测试用例,如Kint,IntScope和SmartFuzz.
危险路径上缺陷的识别path_weakness_detect方法是对weakness_detect方法的扩展,将整数漏洞的判定由整数缺陷的发生扩展到危险路径上的整数缺陷的识别.该方法初步考虑了整数缺陷发生后的行为,检测精度得到一定的提升.与weakness_detect方法相比,因为考虑了危险路径信息,因此可以排除对uncritical INT_WEAK的误报;但与weakness_detect一样,仍然无法排除对denied INT_WEAK的误报,给出的缺陷报告仍需要人工确认. path_weakness_detect方法包括危险路径的抽取和整数缺陷的识别两部分:缺陷识别部分可沿用weakness_ detect方法的成熟技术(如表 2最后一列所描述);危险路径的提取是path_weakness_detect方法的重点,然而会受到指针分析、循环展开和结构体的域敏感等问题的影响[6, 10, 26],难免会产生漏报.如DRIVER[12]的实验结果描述:对于95个已知整数漏洞,DRIVER最多只能准确提取其中86个危险路径.
危险路径上敏感操作使用的异常数值的识别sink_malform_use方法是对path_weakness_detect方法的进一步扩展,将整数漏洞的判定由危险路径上的整数缺陷的发生扩展到敏感操作点使用异常数值,满足T1~T4的充分条件,更全面地考虑了缺陷发生后的行为,理论上是检测精度最高的方法.与weakness_detect和path_ weakness_detect相比,该方法不会产生误报;但与path_weakness_detect方法类似,sink_malform_use方法同样会面临危险路径提取的挑战.此外,判定安全检查代码是否严密是sink_malform_use方法的关键,因为程序员可能提供不完备的安全检查代码(如第1.3.3节讨论).如果对安全代码严密程度的判定出错,则会产生漏报.在现有的检测工作中,仅SIFT属于该类方法,但其过滤对象仅是IO2BO,因此,sink_malform_use方法的实现不够全面,需要扩展到更多的使用模式和漏洞形式中.
3 整数漏洞实例研究针对现实漏洞的实例研究不仅能补充理论研究,还能为漏洞检测方法提供有价值的观察结论.Dietz等人[11]从是否为故意使用和是否为undefined behaviors[13, 23]的角度对SPEC 2000[14]中的整数溢出进行分析;Wang等人[10]针对Linux内核中的整数溢出漏洞进行分析;Coker等人[29]针对5个常用软件讨论整数的使用形式.这些实例研究要么只分析单一漏洞形式[10, 11],要么分析的不是现实漏洞[29].
本节选取CVE[2]于2008年~2013年公布的688个整数漏洞作为研究对象,分析其在漏洞类别上的分布趋势;并针对其中315个开源软件的整数漏洞,从引入原因、使用模式和修复方式上进行深入讨论,以更全面地认识现实整数漏洞的特征.
3.1 漏洞类别的分布趋势本文选取了CVE于2008年~2013年公布的688个整数漏洞作为研究对象,称为full dataset.其中,285个(约41.4%)漏洞存在于商业软件中,另外403个(约58.6%)漏洞存在于开源软件中.图 3描述了4类整数漏洞的百分比堆积柱状图,其中,横坐标分为商业软件和开源软件两部分,分别记录不同年份和总数;纵坐标表示每类整数漏洞的数量占当年总数的比例分布,柱形上的数字为相应漏洞的具体数量.
观察1:总体来说,整数溢出(OF和UF)是整数漏洞的主要部分,商业软件中约84.9%的整数漏洞是整数溢出,开源软件中该比例约为81.9%;其次是符号错误(比例分别为13.0%和15.6%);截断错误数目最少(比例分别仅为2.1%和2.5%).从逐年的数量趋势来看,商业软件和开源软件的分布趋势相似,溢出漏洞都占有绝大部分的比例,符号错误紧随其后,截断错误的数目依旧很少(保持在4个以下,部分年份无截断错误).
观察2:在统计的157个不同的软件商(vendor)中,出现整数漏洞数目较多的包括Apple(69),Microsoft(62), Linux(51),Adobe(48),Google(38),Mozilla(22),Wireshark(20)和GNU(14).大约有74%的软件商仅出现1~2个整数漏洞.
成熟软件出现大量整数漏洞的可能原因是:
1) 成熟软件通常具有代码量大、程序结构复杂的特点,程序员难免会遗漏对其中一些整数操作的安全性分析;此外,复杂的程序结构,也增加了检测方法的分析难度.
2) 软件商如Apple,Microsoft,Google等所提供的是最为常用的软件,针对这些软件的攻击具有很高的商业价值,因此是攻击者的重点攻击对象.
3.2 开源软件中的整数漏洞Full dataset中共有403个整数漏洞存在于开源软件中,但由于部分漏洞没有公布明确的漏洞位置及上下文信息,我们选择其中漏洞信息明确的315个实例作为本节的研究对象,称为open dataset.
3.2.1 漏洞引入原因分布从程序员对整数操作使用的角度,我们将整数漏洞引入原因分为以下5类:
· Not Realize表示程序员没有预期相应变量的数值在运行时会达到能触发漏洞的范围(即range能满足TRIGGER_COND),并没有意识到该整数操作会发生缺陷.
· Incorrect Check表示程序员预期该整数操作可能会触发缺陷,因此选择添加安全检查代码.然而,由于对整数语义的理解不准确,检查代码不严密或者检查代码本身就有缺陷(如第1.3.3节讨论).
· Sign Misuse表示整数类型的符号声明出错,声明的符号与后续所有使用点的符号不同.
· Width Misuse表示整数类型的宽度声明出错,声明的宽度与后续使用点不符合.
· Arch Change表示因程序员没有意识到体系结构的变化,良性的代码被触发为整数漏洞.
具体的分布情况见表 4.
观察3:Not Realize是整数漏洞引入的最主要原因.程序的实际执行违背了程序员的预期,程序员没有预期到这些整数操作的可能取值范围,导致整数漏洞的发生.Incorrect Check引发的整数漏洞也占有很大的比重.
3.2.2 使用模式分布如第1.2.1节讨论,使用模式是指攻击者利用异常数值完成攻击行为的方式.表 5描述了现实漏洞在不同使用模式下的分布情况.
观察4:内存相关的库函数(MEM使用模式)是整数漏洞的主要使用模式,231个(约73.3%)整数漏洞是通过这种方式被攻击者利用来危害程序安全性的.
MEM使用模式涉及内存操作,是程序安全性最敏感的地方,很容易引发缓冲区溢出的攻击,因此,MEM使用模式是攻击者的重点.大量IO2BO漏洞的出现,也引发专门针对IO2BO检测方法的出现,如IntPatch,IntScope, Kint和SIFT等.
3.2.3 修复方式分布由于open dataset中部分整数漏洞没有公布相应的补丁信息,因此,我们选取其中补丁信息明确的291个漏洞实例作为本节的研究对象.我们将整数漏洞的修复方式分为以下7类:
· Precondition表示程序员在发生漏洞的整数操作之前添加操作数是否满足触发漏洞的值范围的检测[11],这是预防整数漏洞发生的一种最有效的修复方式.例如,在无符号加法操作x=o1+o2之前添加if (o1>INT_MAX-o2) error(×)的数值范围检测语句.
· Narrow是指程序员在发生漏洞的整数操作之前添加对操作数的值范围界定.例如,对无符号加法操作x=o1+100之前添加if (o1<200).
· Postcondition是指程序员添加安全检查语句以捕获异常整数数值(如图 2(a)所示).
· Width Extension是指程序员提升操作数的类型宽度,其数值范围也得到相应的扩展,进而能够有效地表示异常整数数值.该修复方式可以修复整数溢出和截断错误.
· Sign Change专门修复由Sign Misuse导致的符号错误,将误用的类型符号修正.
· Format Change通过变更操作符类型以避免漏洞的发生.例如,将a+b>c变更为a>c-b以避免a+b产生的溢出漏洞.
· Remove是指程序员舍弃发生漏洞的代码片段.
具体的分布情况见表 6.
观察5:Precondition和Narrow是从限制操作数取值的角度预防整数漏洞的发生,使其不满足缺陷触发条件(使漏洞判定条件T2失效),约有57.73%的漏洞实例采用此类修复方式.Postcondition阻止异常数值流入敏感操作,使漏洞判定条件T3失效,约有13.40%的漏洞实例采用此类修复方式.
4 挑战与趋势整数漏洞是一个普遍存在且不易察觉的程序安全问题,即使是经验丰富的程序员编写的成熟软件也难以避免整数漏洞(观察2).针对整数漏洞的检测是一个有意义的研究热点,随着大量检测方法的出现(第2节介绍),整数漏洞问题得到一定程度的缓解,但一些关键问题研究仍存在不足之处.具体来说,在整数漏洞研究中仍然存在以下具有挑战性的问题:
(1) 研究防治和避免整数漏洞的编程安全支持技术,以辅助程序员编写更安全的程序代码
Not Realize是整数漏洞引入的最主要原因,一定比重的整数漏洞是由Incorrect Check引发(观察3),并且程序员在修复整数漏洞时容易出错(如第1.3.3节讨论),因此,研究设计完善的针对整数漏洞的安全支持技术以辅助程序员编写更安全的程序代码,是从根本上防止和避免整数漏洞的途径之一.例如:
· 设计全面而准确的整数操作安全规则,指导程序员对关键的数据操作设计严格的取值限制;
· 提供安全的整数漏洞修复模式和详细的修复实例,指导程序员进行漏洞修复工作;
· 提供完善的体系结构变迁日志,明确受体系结构影响的整数操作(如第1.3.1节讨论),当变迁发生时实施代码变更;
· 明确编译器的优化配置,及时排除高优化级别对修复的影响(如第1.3.2节讨论).
(2) 预测和区分整数溢出的故意使用
如第1.3.4节所述,程序员会故意使用整数溢出来实现特殊功能.预测和区分这些故意使用,可以有效地降低检测方法的误报率.然而,根据整数运算操作来推理其语义信息和程序员的意图十分困难,而且当前没有涵盖故意使用溢出的整数漏洞安全模型.因此,如何预测和区分故意使用整数溢出,是当前检测方法亟需解决的问题,将会是下一步的研究热点.
(3) sink_malform_use方法的全面实现(full implementation)
目前,weakness_detect方法已得到很好的应用,DRIVER和SmartFuzz已完成了path_weakness_detect方法的全面实现(见表 2),考虑了所有5类使用模式和所有4类漏洞形式.因此,sink_malform_use方法的全面实现将会是下一步的研究重点.难点在于危险路径的抽取和安全检查语句的严密性判定:首先,与path_weakness_detect方法所面临的困难一样,路径抽取过程会受到指针分析、循环展开和结构体的域敏感等问题的影响,导致危险路径的抽取不完备;其次,如何判定安全检查语句SANITY_CHK是否能捕获异常整数数值,是排除denied INT_ WEAK误报的重点(见定义4),也是sink_malform_use方法的重点(充分条件T3).如果采用动态信息流跟踪(dynamic information tracking)的方法来判断异常整数数值的后续行为,则需要额外开辟内存空间来标记和更新异常数值的状态,严重影响程序的运行速度;如果采用静态约束求解的方法来判断缺陷触发条件和安全检查条件是否能够同时满足,则存在分析精度低和误报率高的问题.
(4) 二进制代码中的整数漏洞检测
在本文的实例研究中,约41.4%的整数漏洞存在于商业软件中(如第3.1节讨论),并且Apple,Microsoft, Adobe等提供的软件中存在大量的整数漏洞(观察2).因此,越来越多的安全研究人员将目光投入到商业软件上,试图在未知源代码的情况下检测整数漏洞.然而与源代码分析方法相比,基于二进制代码的整数漏洞检测方法(如BRICK,IntFinder,IntScope和SmartFuzz)所面临的挑战是如何精确地得到整型变量的符号和宽度信息.二进制代码恢复(binary recovery)技术[39, 40]致力于重构二进制代码的类型和结构信息,将会推进商业软件中整数漏洞的检测进展.
致谢 感谢审稿人的仔细评阅和中肯意见.[1] | Ahmad D. The rising threat of vulnerabilities due to integer errors. IEEE Security & Privacy, 2003,1(4):77-82 . |
[2] | Common vulnerabilities and exposures (CVE). http://cve.mitre.org/ . |
[3] | Definition of ‘vulnerabilty’ in computer science. 2015. http://en.wikipedia.org/wiki/Vulnerability_%28computing%29 . |
[4] | Christey S, Martin RA. Vulnerability type distributions in CVE. 2007. http://cve.mitre.org/docs/vunl-trends/vuln-trends.pdf . |
[5] | Brumley D, Chiueh T, Johnson R, Lin H, Song D. RICH: Automatically protecting against integer-based vulnerabilities. In: Proc. of the 14th Annual Network and Distributed System Security Symp (NDSS). San Diego: Internet Society, 2007. |
[6] | Zhang C, Wang T, Wei TL, Chen Y, Zou W. IntPatch: Automatically fix integer-overflow-to-buffer-overflow vulnerability at compile-time. In: Proc. of the 15th European Conf. on Research in Computer Security (ESORICS). Berlin, Heidelberg: Springer- Verlag, 2010.71-86 . |
[7] | Wang TL, Wei T, Lin ZQ, Zou W. IntScope: Automatically detecting integer overflow vulnerability in x86 binary using symbolic execution. In: Proc. of the 16th Annual Network and Distributed System Security Symp. (NDSS). San Diego: Internet Society, 2009. 1-14. |
[8] | Chen P, Wang Y, Xin Z, Mao B, Xie L. BRICK: A binary tool for run-time detecting and locating integer-based vulnerability. In: Proc. of the 4th Int’l Conf. on Availability, Reliability and Security. 2009. 208-215 . |
[9] | Rodrigues RE, Campos VHS, Pereira FMQ. A fast and low-overhead technique to secure programs against integer overflows. In: Porc. of the IEEE/ACM Int’l Symp. on Code Generation and Optimization (CGO). 2013.1-11 . |
[10] | Wang X, Chen H, Jia Z, Zeldovich N, Kaashoek MF. Improving integer security for systems with KINT. In: Proc. of the 10th USENIX Conf. on Operating Systems Design and Implementation (OSDI). Berkeley: USENIX Association, 2012. 163-177. |
[11] | Dietz W, Li P, Regehr J, Adve V. Understanding integer overflow in C/C++. In: Proc. of the 2012 Int’l Conf. on Software Engineering (ICSE). Piscataway: IEEE Press, 2012.760-770 . |
[12] | Sun H, Li HP, Zeng QK. Statically detect and run-time check integer-based vulnerabilities with information flow. Ruan Jian Xue Bao/Journal of Software, 2013,24(12):2767-2781 (in Chinese with English abstract). http://www.jos.org.cn/1000-9825/4385.htm |
[13] | Wang X, Zeldovich N, Kaashoek MF, Solar-Lezama A. Towards optimization-safe systems: Analyzing the impact of undefined behavior. In: Proc. of the 24th ACM Symp. on Operating Systems Principles (SOSP). New York: ACM Press, 2013.260-275 . |
[14] | SPEC CPU benchmark suites. 2005. http://www.spec.org/cpu2000/ . |
[15] | CUPS integer overflow unerability. 2008. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-1722 . |
[16] | Glibc crafted pattern argument integer overflow vulnerability. 2011. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-1659 . |
[17] | Ruby BigDecimal class truncation vulnerability. 2011. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-0188 . |
[18] | Ghostscript integer underflowvulnerability. 2012. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-4405 . |
[19] | Linux kernel X25 integer underflow vulnerability. 2010. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-4164 . |
[20] | Libmodplug crafted MED file integer overflow vulnerability. 2009. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-1438 . |
[21] | FreeType font file integer overflow vulnerability. 2010. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2500 . |
[22] | Apache 64-bit platform integer overflow vulnerability. 2010. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0010 . |
[23] | Wang X, Chen HG, Cheung A, Jia ZH, Zeldovich N, Kaashoek MF. Undefined behaviors: What happened to my code? In: Proc. of the Asia-Pacific Workshop on System (APSys). New York: ACM Press, 2012. Article No.9 . |
[24] | SafeInt class. 2004. http://safeint.codeplex.com/. |
[25] | IntSafe. 2006. http://blogs.msdn.com/b/michael_howard/archive/2006/02/02/523392.aspx . |
[26] | Molnar D, Li XC, Wagner DA. Dynamic test generation to find integer bugs in x86 binary linux programs. In: Proc. of the 18th USENIX Security Symp. San Diego: USENIX Association, 2009. 67-82. |
[27] | Long F, Douskos S, Kim D, Rinard M. Sound input filter generation for integer overflow errors. In: Porc. of the 41st ACM Symp. on Principles of Programming Languages (POPL). New York: ACM Press, 2014. 439-452 . |
[28] | Seacord R. The CERT C Secure Coding Format. Boston: Addison-Wesley Professional, 2008. 139-201. |
[29] | Coker Z, Hafiz M. Program transforms to fix C integers. In: Proc. of the 2013 Int’l Conf. on Software Engineering (ICSE). Piscataway: IEEE Press, 2013. 792-801. |
[30] | Ranged integer. 2006. http://www.sei.cmu.edu/library/abstracts/reports/07tn027.cfm?RL=library&WT.ac=RLlibrary . |
[31] | Chinchani R, Iyer A, Jayaraman B, Upadhyaya S. ARCHERR: Runtime environment driven program safety. In: Proc. of the 9th European Symp. on Research in Computer Security (ESORICS). Berlin, Heidelberg: Springer-Verlag, 2004.385-406 . |
[32] | Dannenberg R, Dormann W, Keaton D, Plum T, Seacord RC, Svoboda D, Volkovitsky A, Wilson T. AIR: As-if infinitely ranged integer model. Technical Report, CMU/SEI-2009-TN-023, 2009. |
[33] | Wang Y, Ruan D, Tang Z, Xu JP, Wen M. RICF: Dynamic analysis of integer arithmetic overflow vulnerability via finite state machine. Journal of Computational Information Systems, 2010,6(6):1933-1941. |
[34] | Sarkar D, Jagannathan M, Thiagarajan J, Venkatapathy R. Flow-Insensitive static analysis for detecting integer anomalies in programs. In: Proc. of the 25th Conf. on IASTED Int’l Multi-Conf.: Software Engineering. ACTA Press, 2007. 334-340. |
[35] | Chen S, Kalbarczyk Z, Xu J, Iyer RK. A data-driven finite state machine model for analyzing security vulnerabilities. In: Proc. of the 2003 Int’l Conf. on Dependable Systems and Networks (DSN). IEEE Computer Society, 2003.605-614 . |
[36] | Lu XC, Li G, Lu K, Zhang Y. High-Trusted-Software-Oriented automatic testing for integer overflow bugs. Ruan Jian Xue Bao/ Journal of Software, 2010,21(2):179-193 (in Chinese with English abstract). http://www.jos.org.cn/1000-9825/3785.htm |
[37] | Pozza D, Sisto R. A lightweight security analyzer inside GCC. In: Proc. of the 3rd Int’l Conf. on Availability, Reliability and Security (ARES). IEEE Computer Society, 2008. 851-858. [http://dx.doi.org/10.1109/ARES.2008.26] . |
[38] | Chen P, Han H, Wang Y, Shen XB, Yin XC, Mao B, Xie L. Intfinder: Automatically detecting integer bugs in x86 binary program. In: Proc. of the Int’l Conf. on Information and Communications Security. Berlin, Heidelberg: Springer-Verlag, 2009. 336-345 . |
[39] | Lin ZQ, Zhang XY, Xu DY. Automatic reverse engineering of data structures from binary execution. In: Proc. of the 17th Annual Network and Distributed System Security Symp. (NDSS). San Diego: Internet Society, 2010. |
[40] | Slowinska A, Stancescu T, Bos H. Howard: A dynamic excavator for reverse engineering data structures. In: Proc. of the 18th Annual Network and Distributed System Security Symp. (NDSS). San Diego: Internet Society, 2011. |
[12] | 孙浩,李会朋,曾庆凯.基于信息流的整数漏洞插装和验证.软件学报,2013,24(12):2767-2781. http://www.jos.org.cn/1000-9825/ 4385.htm |
[36] | 卢锡城,李根,卢凯,张英.面向高可信软件的整数溢出错误的自动化测试.软件学报,2010,21(2):179-193. http://www.jos.org.cn/1000-9825/3785.htm |