我正在试验shellcode,偶然发现了nop-slide技术。 我写了一个小工具,它将缓冲区大小作为参数,并像这样构造一个缓冲区:[NOP | SC | RET],NOP占用缓冲区的一半,接着是shellcode,剩下的部分填充(猜测的)返回地址。 它与他的着名论文中描述的工具aleph1非常相似。
我脆弱的testing应用程序与他的论文中一样:
int main(int argc, char **argv) { char little_array[512]; if(argc>1) strcpy(little_array,argv[1]); return 0; }
我testing了它,它的工作原理:
jth@insecure:~/no_nx_no_aslr$ ./victim $(./exploit 604 0) $ exit
但说实话,我不知道为什么。 好吧,保存下来的eip被按照意图覆盖了,但是我想不是跳进缓冲区,而是跳进argv。
在调用strcpy() 之前, gdb显示了以下地址:
(gdb) if 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) if 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,还有argv和被猜测的地址0xbffff458。
然后,返回后,EIP指向0xbffff458。 但little_buffer驻留在0xbfffefe8,这是1136字节的差异,所以他当然不会执行little_array。 我跟着执行stepi命令,在0xbffff458及之后,他执行NOP并到达shellcode。
我不太清楚为什么会这样。 首先,我纠正他在argv执行我的shellcode,而不是little_array? 装载程序(?)将argv放到堆栈的哪里? 我认为它紧跟在argc之后,但在argc和0xbffff458之间,有620个字节的差距。 他怎么可能成功地在地址0xbffff458处的NOP-Pad上“落地”,这比在0xbffff1ec处保存的eip高出多less?
有人可以澄清这一点? 我其实不知道为什么这个工作。 我的testing机器是没有ASLR的Ubuntu 9.10 32位机器。 受害者有一个可执行的堆栈,用execstack -s来设置。
提前致谢。
首先,图表堆栈。
0xBFFFF4F9 | | ---------- ... 0xBFFFF29E | NOP | 0xBFFFF29D | NOP | argv [1] *很遗憾 ---------- 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个,取决于存储在内部的类型)
装载程序(?)将argv放到堆栈的哪里?
在调用strcpy
之后, argc
和argv
被覆盖,表明它们可能在little_array
。 我把它们放在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]
),可以执行,具体取决于您猜测的返回地址。
我认为[argv]紧跟在argc后面,但在argc和0xbffff458之间,有620个字节的间隙。
0xBFFFF458是漏洞利用后存储在 argv
的值 (注意argc
与(signed)0xBFFFF458 == -1073744808
)。 之前, argv
拥有0xbffff294。 在这两种情况下, argv
本身都存储在别处。