缓冲区溢出成功,但不应该?

时间:2014-09-14 18:45:14

标签: gdb stack buffer-overflow

这是我的程序,具有易受攻击的char缓冲区,名称[400]。

void greeting(char *temp1,char *temp2)
{
    char name[400];
    strcpy(name,temp2);
    printf("Hello %s %s\n", temp1, name);
}

int main(int argc,char *argv[])
{
    greeting(argv[1],argv[2]);
    return 0;
}

在禁用ASLR的Linux(64位)上编译如下:

gcc -m32 -ggdb -fno-stack-protector -mpreferred-stack-boundary=2 -z execstack -o buffer buffer.c

(gdb) run Mr `perl -e 'print "A" x 400'`
Hello Mr AAAAAAA.... (truncated)
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

(gdb) info reg eip ebp
eip            0x41414141
ebp            0x41414141

我在这里假设添加了一个空字节,导致溢出,但我不明白的是EIP如何只有1字节溢出的0x41414141?

编辑:在使用gdb进行更多探测之后,没有添加空字节,并且只输入400个字节时根本没有溢出。那么我的EIP如何最终指向我的缓冲区内容而没有任何溢出?我假设缺少空字节会导致printf()的问题。

1 个答案:

答案 0 :(得分:2)

C字符串被NUL终止,因此最终会出现1字节溢出,其值为零(NUL)。

单字节NUL溢出将$ebp的保存值修改为指向堆栈下方的值。这会导致将错误的值恢复为$esp,并控制$eip

特别注意ebp的价值。在调用之后,$ebp的值仍然相同,但它指向的值(main将从堆栈中恢复的值)已经调整,并指向我们控制的中间缓冲液中。

greeting返回main时,没有任何反应。但是,当main使用leave指令恢复堆栈帧时,堆栈指针$esp将设置在我们受控缓冲区的中间。执行ret指令后,我们可以控制$eip

请注意,我使用了由pwntools而非标准AAAAA生成的循环模式,因为我们可以使用它来计算偏移量。例如'aaaa'=> 0,'aaab'=> 1,'aaba'=> 2。

在Strcpy之前

EBP: 0xffffc6e8 --> 0xffffc6f8 --> 0x0 
ESP: 0xffffc54c --> 0xffffc558 --> 0xffffc5c8 --> 0xf63d4e2e 
EIP: 0x8048466 (<greeting+25>:  call   0x8048320 <strcpy@plt>)

Strcpy之后

EBP: 0xffffc6e8 --> 0xffffc600 ("raabsaabtaabuaabvaabwaabxaabyaab"...)
ESP: 0xffffc54c --> 0xffffc558 ("aaaabaaacaaadaaaeaaafaaagaaahaaa"...)
EIP: 0x804846b (<greeting+30>:  lea    eax,[ebp-0x190])

leave之前的main

EBP: 0xffffc600 ("raabsaabtaabuaabvaabwaabxaabyaab"...)
ESP: 0xffffc6f0 --> 0xffffc9bb ("Mister")
EIP: 0x80484b1 (<main+39>:      leave)

在主

leave之后
EBP: 0x62616172 (b'raab')
ESP: 0xffffc604 ("saabtaabuaabvaabwaabxaabyaabzaac"...)
EIP: 0x80484b2 (<main+40>:      ret)

在主要

ret
EBP: 0x62616172 (b'raab')
ESP: 0xffffc608 ("taabuaabvaabwaabxaabyaabzaacbaac"...)
EIP: 0x62616173 (b'saab')