我正在尝试使用 shellcode 并偶然发现了 nop-slide 技术。我写了一个小工具,它以缓冲区大小为参数并构造一个像这样的缓冲区:[ 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,所以他肯定用猜测的地址 0xbffff458 覆盖了保存的 ebp、保存的 eip 和 argc 以及 argv。
然后,返回后,EIP 指向 0xbffff458。但是 little_buffer 位于 0xbffffefe8,相差 1136 字节,所以他肯定没有执行 little_array。我使用stepi命令执行,然后,在 0xbffff458 及以后,他执行 NOP 并到达 shellcode。
我不太确定为什么会这样。首先,我是否正确,他在 argv 中执行我的 shellcode,而不是 little_array?加载器(?)将 argv 放在堆栈的什么位置?我以为它紧跟在 argc 之后,但是在 argc 和 0xbffff458 之间,有 620 个字节的间隙。他怎么可能成功地“降落”在地址 0xbffff458 的 NOP-Pad 中,这比保存的 eip 0xbffff1ec 高得多?
有人可以澄清一下吗?我实际上不知道为什么这是有效的。我的测试机器是没有 ASLR 的 Ubuntu 9.10 32 位机器。受害者有一个可执行堆栈,使用 execstack -s 设置。
提前致谢。