• 当前位置:首页>>编程开发A>>安全防御>>bugscam分析
  • bugscam分析
  • 创建时间:2004-02-10
    文章属性:转载
    文章提交:anonymous (wufuzaijia_at_21cn.com)

    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 dea
  • 上一篇:Snort 2.x数据区搜索规则选项的改进
    下一篇:Serv-U "site chmod xxx" Exploit