1 - 前言
确实没有什么新的东西,权且当作读书笔记。
基于静态分析的软件缓冲区溢出漏洞发掘技术主要针对高级语言源代码或汇编代码,它可以在软件发布之前或之后发现一些潜在的安全问题,当然主要是运用到一些开源系统或系统开发人员。在此我们讨论的是把软件缓冲区溢出漏洞发掘抽象为整数范围分析的问题,且只针对C语言源代码。关于整数范围限制的缓冲区溢出漏洞发掘技术,详情请参见[1]。
相信大家对软件缓冲区溢出问题都有一定的了解,在此不对其背景及原理做详细的介绍。国内的朋友可以到[2]和[3]查阅一些相关的技术文献,也可以到[4]浏览最新的缓冲区溢出漏洞信息。
2 - 原型简介
基于静态源代码分析的缓冲区溢出漏洞发掘技术,它可以发现很多在开发阶段的安全问题,同时也可以发现一些开源系统的软件漏洞。它们主要针对的是源代码的程序分析,这包括一些编译原理相关的知识,如语法分析,语义分析等。
整数范围限制的发掘原型包括了程序源代码分析,数学建摸,系统安全等方面的相关内容。首先是对C语言源代码进行特殊的分析,之后产生整数范围限制,最后对产生的限制进行分析从而筛选出存在安全问题的代码。简单的介绍可以参见[5]。
作为一个原型也就应该存在其一定的实用价值。这个原型正是他们对实际工作分析后的折中选择。整数范围限制的发掘原型也存在一些相关的准确度问题,假阳性和假阴性。所谓的假阳性就是产生错误的警告;假阴性则是遗漏掉安全漏洞。也就是我们通俗所说的误报和漏报情况。作为一个折中,它选择了精确度与可测量度之间的相对平衡,这样就增加了对实际大系统分析的可行性。
在原型中提出了他们的两个新观点:
⑴ 将C字符串看作抽象数据类型;
⑵ 将缓冲区视为整数范围对,包括分配范围和使用范围;
将分配给字符串变量的缓冲区长度定义为alloc(s),字符串变量当前使用的缓冲区长度定义为len(s),s为系统中定义的字符串变量。
如果软件当前使用的缓冲区长度len(s)大于系统为起分配的缓冲区长度alloc(s),那么就有可能存在缓冲区溢出漏洞,至于是否可以被利用暂时不做考虑,这又是一个自动化分析衡量的难题。在考虑缓冲区长度的同时,也必须注意到缓冲区的位置,也就是与变量相关的缓冲区范围的长度与位置。这样,对软件缓冲区溢出漏洞的发掘也就成了对整数范围的追踪问题。
整个工作分为两部分,其一是对字符串操作产生相应的整数范围限制;其二则是对产生的限制进行快速而准确的分析,得到最后的漏洞报告信息。
限制语言的详细数学描述与表示请参见[1]。
3 - 整数限制产生
分析C语言源代码使用的是工具集BANE[6]。它通过追踪C代码的分析树来产生整数范围限制的。为了方便起见,字符串的长度包含了结束符。这样一个比较安全的表达式就是 len(s) ≤ alloc(s)。对字符串的操作,其自身定义了一系列的对应匹配表达式,当源代码中出现了相应的语句时,就查找表中对应的整数范围限制表达式。
这些匹配的表达式对应的C语言语句包括:char s[n],strlen(s),strcpy(dst,src),strncpy(dst,src,n),s = "foo",p = malloc(n),p = strdup(s),strcat(s,suffix),strncat(s,suffix,n),p = getenv(...),gets(s),fgets(s,n,...),sprintf(dst,"%s",src),sprintf(dst,"%d",n),snprintf(dst,n,"%s",src),p[n] = ,p = strchr(s,c),h = gethostbyname(...)等等。
为了可测量性和易实现性,他们使用了非流敏感的分析方法,也就是忽略代码中的控制流和表达式顺序。我们可以很容易的想到,这样的方式很容易造成分析的不准确性。如程序中的循环语句,它们中可能含有一些相对重复的语句,可能就会产生一些错误的分析结果,或遗失一些分析结果。基于流敏感的类型限制,大家可以参见[7]。
但是在他们的原型中,函数strcat()被做了特殊的处理,对所有出现strcat()的地方都标志为潜在的安全漏洞隐患。
下面我们来看看原型的分析方式,定义len(s)的范围为[a,b],且alloc(s)的范围为[c,d],那么就会出现三种可能的情况:
⑴ 如果 b≤c,可以判断字符串s不会发生缓冲区溢出;
⑵ 如果 a>d,字符串s总会发生缓冲区溢出;
⑶ 如果两个范围重叠在一起d>b>c>a,就不能作出肯定的判断,可能存在潜在的缓冲区溢出漏洞;
为了原型的简单易实现,他们舍弃了很多对指针操作的分析,其中未分析的操作就包括指针混淆现象(pointer aliasing),双指针操作,数组指针,函数指针。但因为结构(structure)在C语言中的使用非常广泛,所以特地支持对结构的分析与处理。
4 - 整数限制解决
将缓冲区溢出漏洞发掘看作是整数范围限制的问题,那么就需要一个判断是否存在缓冲区溢出的分析解决方案。他们使用了简单的图论技术来构建一个有效的解决整数范围限制的算法。由于一些图论知识的描述不太方便,在此不对其做太多深入的分析。
针对限制系统的解决方案为我们提供了每个变量的边界范围,但是没有给出变量之间的关联关系。这样可以减轻一些分析负担而容易实现,但也会漏掉一些安全问题。目前比较简单的安全问题可能是因为一个变量的不正当使用而造成的,但复杂的安全问题则往往是由一个错综复杂的关系而产生的,这也是本原型的一些局限性。
首先产生一个有向图,每个顶点对应程序中的一个变量。针对每个变量所产生的限制关系则以有向边的形式在有向图中表现出来。解决方案通过在有向图中传播一些信息来释放一些关系,最后得到简化的与漏洞发掘本质相关的有向图。
如果最后产生的有向图是循环的,那么通过拓扑结构给图分类,然后将信息在有向图中经分类后的有向边传播。
他们提出了三种针对循环有向图的解决方案:
⑴ 约束那些会导致循环限制系统的程序;
⑵ 引入一种对产生循环的变量的放宽操作,它可以避免无穷上升链;
⑶ 使用限制语言中的特别域信息来直接处理循环相关的限制系统;
由于前两种方案的各种弊端,最后选择了第三种解决方案。因为第一种方案不切实际,现实程序中总是存在很多的循环与递归的;第二种方案会产生一些不精确的结果。
最后他们得出了一个定律就是可以在线性时间内解决存在循环的限制系统。
5 - 结论
在性能方面,本原型还有很多需要优化的地方,虽然现在已经是一个可用的系统了。原型因为产生了过多的调试信息,这为后期的分析带来了较大的工作量。今后可以在降低分析时间方面做一些努力的尝试。
最大的局限性就是不精确的范围分析而导致过多的误报。这是目前很多漏洞发掘原型/工具共同面对的问题,也就是在建立抽象模型时没有很好的解决范围分析的精确性问题,但其为我们也提供了很多切实可用的信息,这比完全的人工审计已经提高了很多了。如果能够为它提供足够的时间来分析产生的整数范围限制,那么在精确度方面的效果应该会好很多。
还存在的一个问题就是漏报,目前还不能很好地测量漏报率。同时限制系统的解决结果也并不能为人员提供足够详细的漏洞情况。
作为一个自动化的软件缓冲区溢出漏洞静态分析原型,它已经是比较不错的了,虽然有很多需要改进的地方,但毕竟可以减轻人员审计的大量时间和精力。个人认为如果要提高漏洞发掘的精确度,除了对缓冲区溢出漏洞发掘的原理有深入理解和认识的同时,还需要有很深的抽象能力,才能产生真正切实有效的思路和方法。