堆栈缓冲区溢出导致奇怪的执行路径

时间:2012-03-02 09:37:40

标签: c buffer-overflow

我阅读了一些关于Stack Buffer Overflow的文章,比如this一篇,并了解了攻击者如何通过覆盖函数指针来利用Stack Buffer-Overflow错误。然后我写了一个小程序来演示攻击:

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

void fun1 ( char * input ) {
    char buffer[10];
    strcpy( buffer, input );
    printf( "In fun1, buffer= %s\n", buffer );
}

void fun2 ( void ) {
    printf ( "HELLO fun2!\n" );
}

int main ( int argc, char * argv[] )
{
    printf ( "Address of fun2: %p\n", fun2 );
    fun1( "abcdefghijklmnopqrstuv\x52\x84\x04\x08" );
    return 0;
}

该程序是在Fedora 14 x86下使用GCC 4.5.1编译的。以下是输出:

  

$ ./exp01

     

fun2的地址:0x8048452

     

在fun1中,buffer =abcdefghijklmnopqrstuvR

     

HELLO fun2!

     

HELLO fun2!

我们可以看到fun2()被成功调用,但我不知道为什么它会运行两次。然后我GDB了它(见下文)。 (我只知道一些关于GDB的基本指令(¯▽¯)╭)

我用Google搜索了一些关键词,例如“__libc_csu_fini()”,但没有找到一种明确的方法可以帮助我理解程序的执行路径。我对编译器和进程的内部结构知之甚少,所以我认为我可能必须找到一些详细描述这些内容的书籍或文章。有什么建议吗?谢谢!


GDB记录:

  

(gdb)列表

     

7 printf(“在fun1中,缓冲区=%s \ n”,缓冲区);

     

8}

     

9

     

10 void fun2(void){

     

11 printf(“HELLO fun2!\ n”);

     

12}

     

13

     

14 int main(int argc,char * argv [])

     

15 {

     

16 printf(“fun2的地址:%p \ n”,fun2);

     

(gdb)

     

17 fun1(“abcdefghijklmnopqrstuv \ x52 \ x84 \ x04 \ x08”);

     

18返回0;

     

19}

     

(gdb)中断16

     

断点1位于0x804846f:文件hello.c,第16行。

     

(gdb)运行

     

启动程序:/ home / yuliang / test / hello

     

hello.c处的断点1,main(argc = 1,argv = 0xbffff394):16

     

16 printf(“fun2的地址:%p \ n”,fun2);

     

缺少单独的debuginfos,请使用:debuginfo-install glibc-2.13-2.i686

     

(gdb)步骤

     

fun2的地址:0x8048452

     

17 fun1(“abcdefghijklmnopqrstuv \ x52 \ x84 \ x04 \ x08”);

     

(gdb)

     

fun1(输入= 0x804859a“abcdefghijklmnopqrstuvR \ 204 \ 004 \ b”)在hello.c:6

     

6 strcpy(缓冲区,输入);

     

(gdb)

     

7 printf(“在fun1中,缓冲区=%s \ n”,缓冲区);

     

(gdb)

     

在fun1中,buffer =abcdefghijklmnopqrstuvR

     

8}

     

(gdb)

     

hello.c上的fun2():10

     

10 void fun2(void){

     

(gdb)

     

11 printf(“HELLO fun2!\ n”);

     

(gdb)

     

HELLO fun2!

     

12}

     

(gdb)

     __libc_csu_fini()

中的

0x08048500      

(gdb)

     

单步执行直到退出函数__libc_csu_fini,

     

没有行号信息。

     

hello.c上的fun2():10

     

10 void fun2(void){

     

(gdb)

     

11 printf(“HELLO fun2!\ n”);

     

(gdb)

     

HELLO fun2!

     

12}

     

(gdb)

     

无法访问地址0x76757477

的内存      

(gdb)

     

单步执行直到退出函数__libc_csu_init,

     

没有行号信息。

     来自/lib/libc.so.6的__libc_start_main()中的

0x009aae36

     

(gdb)

     

单步执行直到退出函数__libc_start_main,

     

没有行号信息。

     

程序退出,代码为0241。

     

(gdb)

1 个答案:

答案 0 :(得分:0)

strcpy()之前不久在gdb中运行程序并查看堆栈框架(存储保存文件的位置)。然后运行到printf()后不久,再次查看存储的eip(命令为info frame)。

因为你将函数fun2()的地址传递给fun1(),它将覆盖保存的eip,一旦调用return(在你的情况下隐含),就会执行下一条指令(给出通过eip,在您的情况下,它是fun2()

的地址

不要忘记阅读aleph1的Smashing the stack for fun and profit