我正在尝试shellcode,偶然发现了nop-slide技术.我写了一个小工具,将buffer-size作为参数并像这样构造一个缓冲区:[NOP | SC | RET],NOP占用缓冲区的一半,然后是shellcode,其余的则填充(猜测的)返回地址.它与他的著名论文中描述的工具aleph1非常相似.
我脆弱的测试应用程序与他的论文相同:
int main(int argc, char **argv) {
char little_array[512];
if(argc>1)
strcpy(little_array,argv[1]);
return 0;
}
我测试了一下,效果很好:
jth@insecure:~/no_nx_no_aslr$./victim $(./exploit 604 0)
$exit
但老实说,我不知道为什么.好的,保存的eip已按预期被覆盖,但我认为它没有跳到缓冲区中,而是跳到了argv中.
gdb在调用strcpy()之前显示了以下地址:
(gdb) i f
Stack level 0, frame at 0xbffff1f0:
eip = 0x80483ed in main (victim.c:7); saved eip 0x154b56
source language c.
Arglist at 0xbffff1e8, args: argc=2, argv=0xbffff294
Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0
Saved registers:
ebp at 0xbffff1e8, eip at 0xbffff1ec
little_array的地址:
(gdb) print &little_array[0]
$1 = 0xbfffefe8 "\020"
在strcpy()之后:
(gdb) i f
Stack level 0, frame at 0xbffff1f0:
eip = 0x804840d in main (victim.c:10); saved eip 0xbffff458
source language c.
Arglist at 0xbffff1e8, args: argc=-1073744808, argv=0xbffff458
Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0
Saved registers:
ebp at 0xbffff1e8, eip at 0xbffff1ec
那么,这里发生了什么?我使用了604字节的缓冲区来溢出little_array,因此他当然重写了保存的ebp,保存的eip和argc以及带有猜测地址0xbffff458的argv.
然后,返回后,EIP指向0xbffff458.但是little_buffer位于0xbfffefe8,相差1136个字节,因此他当然没有执行little_array.我使用stepi命令跟踪执行,然后从0xbffff458开始,他执行NOP并到达Shellcode.
我不太确定为什么会这样.首先,我是否正确说他在argv中而不是little_array中执行我的shellcode? loader(?)将argv放在哪里?我以为它紧随argc之后,但是在argc和0xbffff458之间,有620个字节的间隙.他怎么可能成功地“降落”在地址为0xbffff458的NOP面板中,该地址比保存的eip高于0xbffff1ec的地址高?
有人可以澄清吗?我实际上不知道为什么这样做.我的测试机器是没有ASLR的Ubuntu 9.10 32位机器.受害者有一个可执行栈,用execstack -s设置.
提前致谢.
解决方法:
首先,绘制堆栈图.
0xBFFFF4F9 | | ---------- ... 0xBFFFF29E | NOP | 0xBFFFF29D | NOP | argv[1] * guestimate ---------- 0xBFFFF29C | '\0' | ... 0xBFFFF295 | '/' | 0xBFFFF294 | '.' | argv[0] "./victim" ---------- ... ---------- 0xBFFFF1F8 | NULL | 0xBFFFF1F8 | &argv[1] | 0xBFFFF1F4 | &argv[0] | argv ---------- 0xBFFFF1F0 | 0x000002 | argc ---------- ... 0xBFFFEFE9 | | 0xBFFFEFE8 | | little_array ----------
(注意:在图中,某些框每行保留1个字节,其他框为4或8,这取决于存储在其中的类型)
And where does the loader(?) place argv onto the stack?
在调用strcpy表明它们可能在little_array之上之后,argc和argv被覆盖.我将它们放置在0xBFFFF1F0处,因为那是堆栈在上一帧结束的地方,而且main的帧中似乎没有空间,即使GDB表示arglist位于0xBFFFF1E8.它依赖于我的系统-argc和argv低于little_array.尝试使用p& argv和p& argc来确定它们的放置位置.
由于0xBFFFF458位于argv [1]中,因此argv [1]中的shellcode确实是要执行的内容,而不是little_array中的内容.由于有两个shell代码副本(一个在little_array中,另一个在argv [1]中),根据您猜测的返回地址,可以执行其中一个.
I thought [argv] follows immediately after argc, but between argc and 0xbffff458, there is a gap of 620 bytes.
0xBFFFF458是漏洞利用后存储在argv中的值(请注意,argc与(带符号的)0xBFFFF458 == -1073744808相同).之前,argv持有0xbffff294.在这两种情况下,argv本身都存储在其他位置.