c - 格式化字符串漏洞 - printf

标签 c string security format

为什么要打印 0x08480110 处内存地址的值?我不确定为什么有 5 个 %08x 参数 - 这会把你带到堆栈的什么地方?

address = 0x08480110
address (encoded as 32 bit le string): "\x10\x01\x48\x08"
printf ("\x10\x01\x48\x08_%08x.%08x.%08x.%08x.%08x|%s|");

这个例子摘自这篇论文的第11页http://crypto.stanford.edu/cs155/papers/formatstring-1.2.pdf

最佳答案

我认为本文提供的 printf() 示例有点令人困惑,因为这些示例使用字符串文字作为格式字符串,而这些示例通常不允许所描述的漏洞类型。此处描述的格式字符串漏洞取决于用户输入提供的格式字符串。

举个例子:

printf ("\x10\x01\x48\x08_%08x.%08x.%08x.%08x.%08x|%s|");

最好呈现为:

/* 
 * in a real program, some user input source would be copied 
 * into the `outstring` buffer 
 */
char outstring[80] = "\x10\x01\x48\x08_%08x.%08x.%08x.%08x.%08x|%s|";

printf(outstring);

由于 outstring 数组是自动的,编译器可能会将其放入堆栈。将用户输入复制到 outstring 数组后,堆栈中的“单词”将如下所示(假设是小端):

outstring[0c]               // etc...
outstring[08] 0x30252e78    // from "x.%0"
outstring[04] 0x3830255f    // from "_%08"
outstring[00] 0x08480110    // from the ""\x10\x01\x48\x08"

编译器会根据需要将其他项目放入堆栈(其他局部变量、保存的寄存器等)。

当即将进行 printf() 调用时,堆栈可能如下所示:

outstring[0c]               // etc...
outstring[08] 0x30252e78    // from "x.%0"
outstring[04] 0x3830255f    // from "_%08"
outstring[00] 0x08480110    // from the ""\x10\x01\x48\x08"
var1
var2
saved ECX
saved EDI

请注意,我完全是在编造这些条目 - 每个编译器都会以不同的方式使用堆栈(因此格式字符串漏洞必须针对特定的确切场景定制制作。换句话说,你不会总是使用5 个虚拟格式说明符,如本例所示 - 作为攻击者,您需要弄清楚特定漏洞需要多少个虚拟格式说明符。

现在调用 printf(),参数(outstring 的地址)被压入堆栈,printf() 是调用,因此堆栈的参数区域如下所示:

outstring[0c]               // etc...
outstring[08] 0x30252e78    // from "x.%0"
outstring[04] 0x3830255f    // from "_%08"
outstring[00] 0x08480110    // from the ""\x10\x01\x48\x08"
var1
var2
var3
saved ECX
saved EDI
&outstring   // the one real argument to `printf()`

然而,printf 并不知道堆栈中有多少参数已被放置在它的堆栈中 - 它根据它在格式字符串中找到的格式说明符(它“肯定”得到的一个参数)进行操作。所以 printf() 获取格式字符串参数并开始处理它。当它到达与我示例中的“保存的 EDI”对应的第一个“%08x”时,下一个“%08x”将打印 保存 ECX' 等等。因此,“%08x”格式说明符只是在吃掉堆栈上的数据,直到它返回到攻击者能够输入的字符串。确定需要多少这些是攻击者通过反复试验来完成的事情(可能通过具有大量“%08x”格式的测试运行,直到他可以“看到”格式字符串的开始位置)。

无论如何,当 printf() 开始处理“%s”格式说明符时,它已经消耗了所有堆栈条目,直到 outstring 缓冲区所在的位置。 “%s”说明符将其堆栈条目视为指针,用户放入该缓冲区的字符串经过精心设计,具有 0x08480110 的二进制表示形式,因此 printf( ) 将以 ASCIIZ 字符串的形式打印出该地址中的任何内容。

关于c - 格式化字符串漏洞 - printf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5672996/

相关文章:

c - 使用 C 确定地址线的数量和 RAM 字的大小

android - 为什么 "tcsetattr(fd, TCSANOW, &cfg)"总是失败?

c++ - 如何转换 int 变量并附加到 const wchar_t*

javascript - 将 CORS 与 AWS API Gateway 结合使用有哪些安全隐患?

c - 带有 %g 和正确的 double 值的 printf 打印出令人讨厌的数字 - 可能是什么原因?

使用 printf 将 int 转换为 char

c#手机格式扩展方法

c# - 向右移动整行字符串

security - Tomcat 7.0.52 APR 1.1.29 native TLS 协议(protocol) session 重新协商安全漏洞 TLS SSL 中间人 CVE-2009-3555

facebook - client_id 的 OAuth2 安全注意事项