缓冲区溢出攻击实验

使用系统环境为:ubuntu10.04 2.6.32-27-generic gcc4.4.3
这里先放出实验代码:

其实这是《深入理解计算机系统》里的一个家庭作业,根据以上代码可以看出getbuf()函数在正常情况下无论怎么调用都会返回值1。任务是只简单地对提示符输入一个适当的十六进制字符串,就使getbuf对rest返回-559038737(0xdeadbeef)。
不过在目前的内核和编译器下要直接对原程序进行栈溢出攻击是不可能完成的了。现在的编译器对代码做了一些防止溢出攻击的保护措施,如%gs:0x14。每次运行程序时它都会随机产生一个类似验证码的值,当函数返回时它会验证此验证码是否被改变,由于它验证码的存放内存位置位于buf数组和保存在栈上的%ebp之间,只要数组一旦越界写入的话就会被改变,这时候也会触使保护代码运行。
不过我在编译时加进了-fno-stack-protector选项,这时候是不产生任何栈溢出保护代码的。
以下是源程序反汇编所得的主要汇编代码:

这里主要需要进行getbuf和test两个函数汇编代码的分析。
分析可以得出:test调用了getbuf函数,getbuf将0x1传送到%eax做为返回值。test将返回值赋值给val,最后以16进制打印出来,这个结果在正常情况下无论如何就只是输出0x1。
这里通过汇编代码我们可以发现两种思路,一种就是在getbuf中输入字符串时,覆盖栈中保存的%ebp值(跟原先的值一样),返回地址(使其直接跳转到test汇编代码的call 80483cc 这一句,以及返回地址上面的8个字节%ebp+4、%ebp+8(这两个是做为printf的两个参数);另外一种就是往buf里注入一段机器码(这段机器码主要是将%eax赋值为0xdeadbeef),当然这时候也需要覆盖返回地址,使其跳转到注入的机器码的起始地址,不过这种方法在目前的内核下并不可行,会引发系统某种保护机制而失败。
这里主要研究第一种思路,下面可以看下test和getbuf的部分栈的组织图。

getbuf里分配了40个字节的空间,不明白为什么需要这么多额外的。
这里主要需要获取%ebp的值,以及call 80483cc 这一句的地址(这个可以从汇编代码里得出为0x80485ab)。
%ebp的值需要调试运行在getbuf函数里面下断点读出。
用gdb调试过程如下:
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3 : GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /home/colaghost/Desktop/test2...done.
(gdb) break *0x804856c
Breakpoint 1 at 0x804856c: file test.c, line 42.
(gdb) r
Starting program: /home/colaghost/Desktop/test2
Breakpoint 1, 0x0804856c in getbuf () at test.c:42
warning: Source file is more recent than executable.
42 {
(gdb) print /x *(int*)($ebp)
$1 = 0xbfffefd8
这里得出保存的%ebp值为0xbfffefd8,下面可以得出要返回0xdeadbeef的字符串。
首先是输入任意40个十六进制字符填满char[12]和额外的8个字节,继续输入保存的%ebp的值,返回地址0x80485ab,printf的第一个参数的存放地址,即 0x80486f1,最后是我们要打印的字符0xdeadbeef。
最终得到的字符串就是这样的:
b8ef bead deba 6985 0408 ffe2 0000 0000 0000 0000 d8ef ffbf ab85 0408 f186 0408 efbe adde
后记:最先由于%gs:0x14,以及系统的一些保护机制,在正确的思路下花费了一整晚的时间都没有任何进展,一直是以sementation fault告终。第二天上午在gdb调试运行状态下才算成功得到返回值。输入同样的字符串,在gdb运行状态下可以得到返回值,并且显示程序正确结束;不过在一般运行状态下test方法返回后一直出现sementation fault的错误,到现在都未找到实际原因。

标签: ,
文章分类 C/C++, Unix/Linux

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*