Chinaunix

标题: 利用堆空间作编译器试验以及对缓冲区溢出的措施(一) [打印本页]

作者: mik    时间: 2008-08-17 01:53
标题: 利用堆空间作编译器试验以及对缓冲区溢出的措施(一)
一、以下是分配一段空间,并假设为编译器对函数的缓冲区溢出作处理的试验。
对缓冲区溢出处理之一是:微软的利用检测 cookie 值来进行处理的技术。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/* 函数表的全局符号表,类似 ELF 格式的 GOT 表格 */

void (*fptr[])() = {
        &strcpy,
        &printf
};


void foo()
{
        char s[4];
        (fptr[0])(s, "aksdfjalsfjaslfjaslf");      /* strcpy(),很明显会导致溢出,覆盖返回值 */

        (fptr[1])("I'm foo()\n");
}


int cookie = 0;                        /* cookie 值 */



/*****  出错出处理例程示例 *********/
void do_fault()
{
        printf("do_fault(): buffer overflow! return addres error\n");
        exit(1);
}


/*** 安插 cookie 例程 ****/
void set_cookie_value(int cookie_addr, char *pos)
{
        pos[0] = 0xff;                                /* push cookie */
        pos[1] = 0x35;
        *((int *)&pos[2]) = cookie_addr;
}


/*** 安插cookie检测例程 ***/
void set_check_fun(int cookie_addr, char *pos)
{
        pos[0] = 0x5a;                                /* pop edx */
        pos[1] = 0x39;                                /* cmp [cookie], edx */
        pos[2] = 0x15;
        *((int *)&pos[3]) = cookie_addr;        
        pos[7] = 0x74;                                /* je +9 : ret */
        pos[8] = 0x07;
        pos[9] = 0xbe;                                /* mov esi, do_fault */
        *((int *)&pos[10]) = (int)do_fault;
        pos[14] = 0xff;                                /* call esi */
        pos[15] = 0xd6;
        pos[16] = 0xc3;
}



char *get_ret(char *buf, int len)
{
        while (len-- && (*buf != (char)0xc3))
                buf++;

        if (len)
                return buf;
        else
                return 0;
}


int main()
{

        cookie = (int)time(0);                /* 随机的 cookie 值 */
       
        char *buf = malloc(200);       /* 分配空间用来作编译试验 */

        set_cookie_value((int)&cookie, buf);  /* 在函数头安插 cookie 信息 */

        memcpy(buf+6, foo, 200);
       
        char *p = get_ret(buf+6, 200);
       
        set_check_fun((int)&cookie, p);      /* 在函数尾安插检测例程 */


        ((void (*)())buf)();                 /* 测试 */

    // foo()                          /* 直接调用 foo(),将产生 segmenation fault */
}


上面的代码示例,利用分配的空间,作函数复制过去,然后假设自己为编译器,对 foo() 函数进行 cookie 安插处理,然后调用经过处理后的 foo() 函数,展示 cookie 是如何对缓冲区溢出应对措施
作者: mik    时间: 2008-08-17 01:56
二、微软的利用 cookie 对缓冲区溢出措施的原理


1、foo() 编译器作处理原理如下:

foo:               <---------- 在此处安插 cookie 值         
        pushl        %ebp
        movl        %esp, %ebp
        subl        $24, %esp
        movl        fptr, %eax
        movl        $.LC0, 4(%esp)
        leal        -4(%ebp), %edx
        movl        %edx, (%esp)
        call        *%eax
        movl        fptr+4, %eax
        movl        $.LC1, (%esp)
        call        *%eax
        leave
        ret                         <---------- 在函数返回前安插检测代码




2、在我写的测试的安插 cookie 处理之后,如下

foo:                
        pushl    cookie                  <---------- 在此处安插 cookie 值
        pushl        %ebp
        movl        %esp, %ebp
        subl        $24, %esp
        movl        fptr, %eax
        movl        $.LC0, 4(%esp)
        leal        -4(%ebp), %edx
        movl        %edx, (%esp)
        call        *%eax
        movl        fptr+4, %eax
        movl        $.LC1, (%esp)
        call        *%eax
        leave

        pop %edx                 <---------- 在函数返回前安插检测代码
        cmpl %edx, cookie
        je 1f
        movl $do_fault, %esi
        call *%esi                /* 出错处理例程 */
1f:
        ret     

作者: mik    时间: 2008-08-17 01:58
三、运行结果测试

1、在 foo() 函数内加入导致溢出的代码,调用经过编译器安插 cookie 处理例程的 foo()函数,
成功检测错误,显示:
I'm foo()
do_fault(): buffer overflow! return addres error


2、当去掉 foo() 函数内导致溢出的代码后,结果和没有出错一样,显示:
I'm foo()



3、调用未经过编译器安插的 cookie 例程 foo() 函数时,将导致 segmenation fault
I'm foo()
segmentation fault



下一次再来试验:直接检测返回值是否被修改,而不用插入 cookie 值!
作者: mik    时间: 2008-08-17 02:03
在微软的 VC8 支持产生 cookie 处理的代码,貌似 gcc 没有这种技术。

偶上面写的代码,是根据 cookie 原理,在 linux 下作出一个小试验
作者: system888net    时间: 2008-08-17 02:30
好,LZ有益的探索. 顶一下.

[ 本帖最后由 system888net 于 2008-8-17 02:43 编辑 ]
作者: bobozhang    时间: 2008-08-17 08:43
gcc一样有,stackguard和stackshieft都可以降低栈受缓冲区溢出攻击的威胁,你上面贴的贴子的方法就是stackguard,但好像不够完整,那个cookie值应该有一个字节为'\0',这样可以防止strcpy这种字符串操作的缓冲区溢出
作者: qliu00    时间: 2008-08-17 08:52
原帖由 bobozhang 于 2008-8-17 08:43 发表
gcc一样有,stackguard和stackshieft都可以降低栈受缓冲区溢出攻击的威胁,你上面贴的贴子的方法就是stackguard,但好像不够完整,那个cookie值应该有一个字节为'\0',这样可以防止strcpy这种字符串操作的缓冲区溢出


cookie值应该有一个字节为'\0',说得很正确
作者: gawk    时间: 2008-08-17 09:11
支持做有益的探索
作者: mik    时间: 2008-08-17 09:31
原帖由 bobozhang 于 2008-8-17 08:43 发表
gcc一样有,stackguard和stackshieft都可以降低栈受缓冲区溢出攻击的威胁,你上面贴的贴子的方法就是stackguard,但好像不够完整,那个cookie值应该有一个字节为'\0',这样可以防止strcpy这种字符串操作的缓冲区溢出

stackguard 应该用什么参数来产生?
cookie 应该是一个整型值,不应是个串。cookie 本身就是为了防止缓冲区溢出,有 '\0' 是多余的。
作者: jamesr    时间: 2008-08-17 09:43
提示: 作者被禁止或删除 内容自动屏蔽
作者: bobozhang    时间: 2008-08-17 09:45
原帖由 mik 于 2008-8-17 09:31 发表

stackguard 应该用什么参数来产生?
cookie 应该是一个整型值,不应是个串。cookie 本身就是为了防止缓冲区溢出,有 '\0' 是多余的。



好像不需要指定什么参数让gcc产生吧,这些gcc是被修改过的。

'\0'好像不一定多于吧?比如我们有个函数调用了strcpy,正好这个strcpy会产生缓冲区溢出,如果攻击者计算出了那个cookie值的话,有'\0'和没有'\0'是不同的。
作者: mik    时间: 2008-08-17 10:00
原帖由 jamesr 于 2008-8-17 09:43 发表
gcc果然有溢出保护:
gcc -fstack-protector-all -Wstack-protector yourfile.c
写了一个最简单的测试:

#include
int main()
{
        char str[3];
        strcpy(str,"hello";
        return ...


果然有此项功能。
但是,貌似cookie不能做随机
作者: mik    时间: 2008-08-17 10:06
原帖由 bobozhang 于 2008-8-17 09:45 发表



好像不需要指定什么参数让gcc产生吧,这些gcc是被修改过的。

'\0'好像不一定多于吧?比如我们有个函数调用了strcpy,正好这个strcpy会产生缓冲区溢出,如果攻击者计算出了那个cookie值的话,有'\0'和没 ...


好的cookie值是个随机性的,微软的cookie值这一点做得比较好,每调用一次cookie都会不同,要计算这个cookie 不那么容易。

话说回来,cookie 技术也不是什么保险的措施。绕过cookie值是完全可以做到的。
作者: bobozhang    时间: 2008-08-17 10:16
原帖由 mik 于 2008-8-17 10:06 发表


好的cookie值是个随机性的,微软的cookie值这一点做得比较好,每调用一次cookie都会不同,要计算这个cookie 不那么容易。

话说回来,cookie 技术也不是什么保险的措施。绕过cookie值是完全可以做到的。


嗯,在有些场合是可以绕过的,但有些场合是绝对绕不过去的
作者: qliu00    时间: 2008-08-17 11:29
原帖由 mik 于 2008-8-17 10:06 发表


好的cookie值是个随机性的,微软的cookie值这一点做得比较好,每调用一次cookie都会不同,要计算这个cookie 不那么容易。

话说回来,cookie 技术也不是什么保险的措施。绕过cookie值是完全可以做到的。


绕过cookie值?最好还是保留,cookie 技术虽然不是什么保险的措施,但通过cookie 技术能
使代码更稳定
作者: 醉卧水云间    时间: 2008-08-17 11:50
研究之前需要对当前的技术有充分的了解.
作者: system888net    时间: 2008-08-17 17:04
security cookie 是windows xp sp2和win 2003 和以后的版本才引入的,而且windows2003
中 跟 windows2003 spx(x>=1) 的保护细节也有些区别.

继续关注大家对linux和windows 下堆栈缓冲区溢出保护机制的观点.
作者: system888net    时间: 2008-08-17 18:23
原帖由 bobozhang 于 2008-8-17 10:16 发表


嗯,在有些场合是可以绕过的,但有些场合是绝对绕不过去的


能否举例说明"但有些场合是绝对绕不过去的" 的观点.
作者: lukeden    时间: 2008-08-17 18:27
不懂,学习了
作者: bobozhang    时间: 2008-08-17 19:11
原帖由 system888net 于 2008-8-17 18:23 发表


能否举例说明"但有些场合是绝对绕不过去的" 的观点.


我说绕不过是指攻击者无法成功攻击

比如一个简单的如下程序在一个用cookie保护的系统上,我想没人能够成功利用这个缓冲区溢出而攻击吧

int main(int argc, char *argv[])
{
        char        buf[8];

        strcpy(buf, argv[1]);

        return 0;
}

作者: system888net    时间: 2008-08-19 00:43
原帖由 bobozhang 于 2008-8-17 19:11 发表


我说绕不过是指攻击者无法成功攻击

比如一个简单的如下程序在一个用cookie保护的系统上,我想没人能够成功利用这个缓冲区溢出而攻击吧

int main(int argc, char *argv[])
{
        char        bu ...



ok,明白你的观点了.
作者: mik    时间: 2008-08-21 00:16
刚刚发现的 gcc 应对缓冲区溢出改写返回地址的另一个措施

int main()
{
}


main:
        leal        4(%esp), %ecx
        andl        $-16, %esp
        pushl        -4(%ecx)
        pushl        %ebp
        movl        %esp, %ebp
        pushl        %ecx
        popl        %ecx
        popl        %ebp
        leal        -4(%ecx), %esp
        ret


利用双重返回地址,若溢出代码改写了返回地址,还有后着:还有一个返回地址。
作者: system888net    时间: 2008-08-21 01:06
原帖由 mik 于 2008-8-21 00:16 发表
刚刚发现的 gcc 应对缓冲区溢出改写返回地址的另一个措施

int main()
{
}


main:
        leal        4(%esp), %ecx
        andl        $-16, %esp
        pushl        -4(%ecx)
        pushl        %ebp
        movl        %esp, %ebp
        pushl        %ecx
        popl        %ec ...


LZ越来越深入了, 顶一下. 希望继续.
作者: crspo    时间: 2008-08-21 17:16
貌似使用硬件的NX bit,比使用软件的保护措施更加完全并且有效!
作者: westmylove    时间: 2008-08-21 18:11

先做个标记,回头再看。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2