跳进argv?

我正在试验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之后, argcargv被覆盖,表明它们可能在little_array 。 我把它们放在0xBFFFF1F0,因为这是堆栈结束前一帧的地方,似乎没有空间在main框架,即使GDB说arglist位于0xBFFFF1E8。 它欺骗了我的系统 – argcargv低于little_array。 试试p &argvp &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本身都存储在别处。