bugscam分析kkqq(kk_qq@263.net)
http://www.0x557.org
http://blog.0x557.org/kkqq/
-- [ 目录
1.简介
2.检查的模式
2.1 缓冲区溢出的检查
2.2 格式化字符串的检查
3.难点分析
3.1 缓冲区长度的确定
3.2 误报的情况
4.一些展望
5.参考
-- [ 简介
bugscam[1]是一个基于IDA Pro idc脚本机制的轻量级的漏洞分析工具。
之所以说他是轻量级的,是因为只能检查出一些比较简单的编程错误。这里我
们对bugscam实现上的一些机制进行简单的分析,并对bugscam的局限性做一些
评论。关于bugscam的简单介绍,可以参考[2]。
这里就不介绍关于IDA Pro和idc脚本机制的背景知识了,这些资料可以参
考[3]一书和IDA Pro的在线帮助[4]。
-- [ 检查的模式
bugscam采取的是针对可能导致缓冲区溢出和格式化字符串的库函数进行
检查的方式来确定程序中是否存在安全隐患。相对于源码级的安全审核工具
中splint[5]等等来说,是一样的原理,只不过bugscam是汇编级的检查,本身
又借助了IDA Pro这个强大的反汇编平台。
这里简单的列一下bugscam检查的模式,相信很多朋友对下边的模式都已
经了熟于心。
---- [ 缓冲区溢出的检查
1.最常见的就是如下的两种模式了
strcpy(dst, src);
strcat(dst, src);
这里bugscam判断的算法很简单,如果dst的长度小于src的长度,那么就可
以认为这里有缓冲区溢出的问题。(注意:只是存在缓冲区溢出的问题,并不等同
于这就是一个可以利用的漏洞,如何使用自动化工具判断漏洞是否可以利用,
这又是另外的一个大问题。)
2.MultiByteToWideChar的检查,在windows平台上,最常见的错误可能就是
单字节和双字节的转化中出的问题了。MultiByteToWideChar就是这样的例子。
判断的规则很简单,如果sizeof(dst) < sizeof(src) * 2那么就被判断可
能存在缓冲区溢出的问题。
3.还有一种算是比较隐含的错误,但是也比较常见的错误类型。
sprintf(dst, "%s", src);
其实,这个是等同于strcpy(dst, src),当然有可能sprintf的格式串不是
单纯的"%s",有可能是"%s: No such file or directory."之类的:)
判断的算法也很简单,sizeof(dst) < sizeof(src)。这里当然会有一点误
差,bugscam里边没有详细计算格式化串中字符占的长度。而且对%.xs(x表示数
字)之类的判断也没有做完。
---- [ 格式化字符串的检查
这个简单的不能再简单了,就是检查sprintf的第二个参数是静态字符串还
是动态分配的字符串。可惜这个在release的版本中也是只看到影子,具体也没
有实现。
从上边这些简单的模式来看,bugscam似乎是一个很不照的工具。但是想想
Halvar Flake的初衷就可以理解这些问题。下边是从bugscam的readme中截取的。
"It's release was inspired by the fact that I had libaudit.idc
(the "core" engine) lying on my harddisk since early 2001, and never
thought someone would bother with something this simple -- but now in
2003 one can find commercial products with almost identical
functionality on the Web, and as such I decided to release this as
OpenSource. "
所以buscam是一个Prove of Concept Code,并不是一个完美的工具。至于
那个商业化的工具是什么呢?在OYXin的大力帮助下,这里八卦一下,可能就是
bugscan[6]。OYXin还真正体验了一把万恶的资本家向钱看的冷漠无情。
-- [ 难点分析
其实对普通的程序进行上边几种模式的检查,理论上来说就可以发现不少
问题了(看看ms现在的漏洞,大部分也还是这种低级层次的问题,当然这种问题
会不断的少下去)。但是用过bugscam的朋友就知道,bugscam输出的报告中大部
分的信息都是无用的。技术的角度来说,这就是汇遍级模式普遍都存在的一些
问题。
c语言不像Java一样是一种严格的类型语言。c语言中的字符串类型是没有
长度这个属性的,除此之外c语言中指针被赋予的灵活性,也是这些难点的根本
所在。针对二进制分析更为困难的是,汇编中根本就没有类型这个东西,只有
地址和地址内容。
bugscam效率不高的原因主要有两个,无法精确得到缓冲区长度和误报。有
点类似于IDS系统中的误报和漏报。
---- [ 缓冲区长度的确定
bugscam根据缓冲区所在位置的不同,提供了几个确定缓冲区的长度:
static GetArgBufSize(eaCall, iArgnum);
static StckBuffSize(lpCall, cName);
static StrucBuffSize(strucID, cName);
static SHeapBuffSize(eaBuff);
以上的这些功能其实都基于一个最核心的函数:
static BuffSize(eaInstruc, iOpnum)
(以上函数都在libaudit.idc中)
这些函数其实都没有什么好分析的,这里简单起见,我们把确定缓冲
区长度的核心思想说一下。这里以栈中的缓冲区分配为例:
.text:0041C86C sub_41c86c proc near
.text:0041C86C
.text:0041C86C statbuf = byte ptr -1030h
.text:0041C86C var_101E = dword ptr -101Eh
.text:0041C86C var_101A = dword ptr -101Ah
.text:0041C86C dst = byte ptr -1008h
.text:0041C86C var_808 = byte ptr -808h
.text:0041C86C var_8 = dword ptr -8
.text:0041C86C var_4 = dword ptr -4
.text:0041C86C arg_0 = dword ptr 8
可以看到栈中现在有7个区域,分别从var_4,var_8一直到statbuf。
每个栈都有特定的区域。总的栈空间可以从sub esp xxx和add esp xxx指
令中计算得到,而每个区域又是靠在这个函数那通过esp基址加偏移量的引
用得到,比如函数内部有一个
lea eax, [ebp-808h]
形式的指令,那么可以判断ebp-808就是一个栈分配区域。这样也就
确定了函数栈空间有一个var_808的变量。分析完函数那所有的这些东西
之后也就确定了函数的栈空间分配(这些是ida自动完成的)。
看到这里,大家也就知道了缓冲区的长度是怎么确定了。比如要确定
dst区域的大小,那么就是1008h - 808h = 1000h长了。原理就这么简单
其他诸如data段数据确定也是一样。
bugscam的ReadMe里边有一句话:
"Inspect manually to remove false positives, use the
ObjRec package (or something similar) to reconstruct
structures & objects in order to further decrease
false postives"
ObjRec就是Halvar Flake利用上述原理写的一个逆向工程binary中可
能定义的struct的工具,所以两个搭配,如果缓冲区是结构中的某一个变
量,效果会很不错。具体的资料可以参考[7]。
---- [ 误报的情况
仔细想一想就知道上边这种方法的缺陷。比如我们经常会写类似如下
形式的代码:
char *pRequest = "GET / HTTP/1.1"
char *pContext = pRequest + 4;
利用上边的方法确定缓冲区就会吃亏了。因为pRequest和pRequest + 4
都是一个引用到的地址,这样判断出来的缓冲区就会分解成一个长度为4和
长度为strlen("GET / HTTP/1.1") - 4的缓冲区了。所以bugscam生成的报
告里边出现缓冲区长度为2,3这样10以内的缓冲区,很大一部分都是误报。
还有的情况就是无法确定缓冲区的长度,这个具体扫一眼代码就知道是
什么类型了,例如GetArgBufSize中的代码:
if(strstr(cOpnd, "[") != -1)
{
return(0);
Message("can deal with \"[\"\n");
}
形如push [eax]这样的代码,就没有办法搞了。且不说静态分析没有运行
时的信息,光是回溯eax的赋值就够你受的,慢慢就会发现是在逆向工程程序
的算法,这个有源码都困难,更不要说汇编了:)。(这里说得是工具,不是说
人分析困难,人的力量是无穷的:))
这些是汇编语言上的限制,很难想出什么切实可行的方法。另外还有一些
和api接口相关的限制。比如windows平台上,字符串有时是作为资源存在的。
而字符串的获取在程序中是通过LoadString之类的api调用获得的。在这种情况
下,要确定这种字符串的长度以及内容(比如检查是否有%s之类的格式串)相对
就很困难,如果要实现的话就是要实现一个对binary中资源文件的解析。幸运
的是这种问题在*nix上相对存在比较少。
-- [ 一些展望
受到目前反汇编技术的局限,bugscam注定了只能有这样子的功能。但是
我个人觉得这种工具又是不可缺少的,因为确实可以检查出一些简单模式的
漏洞。只要能减少体力劳动的工具都是有用的。在具体的分析过程中,先用
bugscam扫描一遍,可以排除不少跟本不可能会有问题的函数调用,幸运的
话,也可以找到漏洞。
bugscam目前的限制在于只是一个原型代码,可以改进的地方一个是加入
更多的可以匹配的模式,另外一个就是在反汇编技术允许的范围内完善确定
确定缓冲区大小的算法。很不幸的是Halvar Flake本人对bugscam的完善也
不是很关心,他不是很看好这个东西的前景,他认为静态分析如果想更有
效的话,需要一个更为强大的逆向工程平台,现在IDA Pro是远远不够的。
其实想一想SPLINT这种源代码审查工具都做不到精确度很高,汇编级的东
西就是奢谈了。
写文章的过程中得到OYXin和N.E.V.E.R的支持,在此连同参考中资料的
作者一并表示感谢。
(其实没什么技术含量,所以里边加了一些乱七八糟八卦的东西:))
-- [ 参考
[1] BugScam IDC Package
http://sourceforge.net/projects/bugscam
[2] BugScam简介
http://www.nsfocus.net/index.php?act=sec_tool&do=view&tool_id=389&keyword=
[3] 加密与解密(第二版)
http://www.china-pub.com/computers/common/info.asp?id=12210
[4] DataRescue IDA Pro Disassembler Page : Support and FAQ
http://www.datarescue.com/idabase/idasupport.htm
[5] SPLINT
http://splint.org/
[6] BugScan: Automated Software Security Analysis
http://www.hbgary.com/index.asp?G1=2&G2=1
[7] Auditing Binaries For Security Vulnerabilities
http://www.blackhat.com/html/bh-consulting/bh-consulting-tools.html
http://www.blackhat.com/presentations/win-usa-01/Halvar/bh-win-01-halvar-flake.ppt
$Id: bugscam.txt,v 1.2 2003/12/13 11:00:09 yclin Exp $
Posted by kkqq at February 1, 2004 03:26 AM