是的,已经存在很多类似的问题(5037601、19166698、4855162、14505995、5052648、13409508、7745146、7459630;抱歉,没有足够的代表超过 2 个链接),是的,有一些很好的文章解释了这种东西(点击,点击,http://codearcana.com/posts/2013/05/02/introduction-to-format-string-exploits.html)。我已经阅读了它们并且我想我明白了一般的想法,但是我仍然无法成功地利用我能想到的最简单的训练玩具示例。
#include <stdio.h>
void f(char* a)
{
printf("a: %p\n", &a);
printf(a);
return;
}
void main(int argc, char** argv)
{
f(argv[1]); //please ignore the lack of any check
return;
}
是的,堆栈是可执行的,是的,内存布局随机化被禁用。每次执行都给我相同的地址a
。例如$ ruby -e 'print "AAAA"+("%08x."*16)'
,我可以喂它,结果是:
a: 0xbfffece0
AAAAbfffece0.bfffecf0.b7fd7ff4.00000000.00000000.bffffcf8.080484b0.bfffecf0.00000fff.b7fd8420.00000000.41414141.78383025.3830252e.30252e78.252e7838.
所以现在我可以看到我的输入在内存中的最终位置。我可以使用 将值写入堆栈$ ruby -e 'print "12345%n"+("%08x."*16)'
,结果如下:
a: 0xbfffece0
12345bfffecf0.b7fd7ff4.00000000.00000000.bffffcf8.080484b0.00000005.00000fff.b7fd8420.00000000.34333231.256e2535.2e783830.78383025.3830252e.30252e78.
显然,我的最终目标大概是这样<something><NOPs><shellcode>
的,<something>
覆盖返回地址,f
以便程序跳转到 NOP sled 并执行 shellcode。但是现在保存的返回地址的地址似乎取决于我的输入,对吧?类似于 的东西0xbfffece0 - len(input) - 12
,假设是 12 字节的序言?也许这个例子毕竟不是最简单的......
我越来越糊涂了。有任何想法吗?