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 |