格式字符串漏洞 - printf [英] format string vulnerability - printf

查看:17
本文介绍了格式字符串漏洞 - printf的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Why does this print the value of the memory address at 0x08480110? I'm not sure why there are 5 %08x arguments - where does that take you up the stack?

address = 0x08480110
address (encoded as 32 bit le string): "x10x01x48x08"
printf ("x10x01x48x08_%08x.%08x.%08x.%08x.%08x|%s|");

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

This example is taken from page 11 of this paper http://crypto.stanford.edu/cs155/papers/formatstring-1.2.pdf

推荐答案

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

I think that the paper provides its printf() examples in a somewhat confusing way because the examples use string literals for format strings, and those don't generally permit the type of vulnerability being described. The format string vulnerability as described here depends on the format string being provided by user input.

所以例子:

printf ("x10x01x48x08_%08x.%08x.%08x.%08x.%08x|%s|");

最好表述为:

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

printf(outstring);

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

Since the outstring array is an automatic, the compiler will likely put it on the stack. After copying the user input to the outstring array, it'll look like the following as 'words' on the stack (assuming little endian):

outstring[0c]               // etc...
outstring[08] 0x30252e78    // from "x.%0"
outstring[04] 0x3830255f    // from "_%08"
outstring[00] 0x08480110    // from the ""x10x01x48x08"

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

The compiler will put other items on the stack as it sees fit (other local variables, saved registers, whatever).

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

When the printf() call is about to be made, the stack might look like:

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

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

Note that I'm completely making those entries up - each compiler will use the stack in different ways (so a format string vulnerability has to be custom crafted for a particular exact scenario. In other words, you won't always use 5 dummy format specifiers like in this example - as the attacker you'd need to figure out how many dummies the particular vulnerability would need.

现在调用 printf(),参数(outstring 的地址)被压入堆栈,printf() 是调用,所以堆栈的参数区域看起来像:

Now to call printf(), the argument (the address of outstring) is pushed on to the stack and printf() is called, so the argument area of the stack looks like:

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

然而,printf 并不真正知道堆栈中为其放置了多少参数 - 它通过在格式字符串中找到的格式说明符(它肯定"得到的一个参数).所以 printf() 获取格式字符串参数并开始处理它.在我的示例中,当它到达与保存的 EDI"相对应的第一个%08x"时,下一个%08x"将打印保存ECX'等等.所以%08x"格式说明符只是在吃掉堆栈上的数据,直到它回到攻击者能够输入的字符串.确定需要多少这些是攻击者会通过一种试错法来做的事情(可能是通过具有大量%08x"格式的测试运行,直到他可以看到"格式字符串的开始位置).

However, printf doesn't really know anything about how many arguments have been placed on the stack for it - it goes by the format specifiers it finds in the format string (the one argument it's 'sure' to get). So printf() gets the format string argument and starts processing it. When it gets to the 1st "%08x" that will correspond to the 'saved EDI' in my example, then next "%08x" will print the saved ECX' and so on. So the "%08x" format specifiers are just eating up data on the stack until it gets back to the string the attacker was able to input. Determining how many of those are needed is something an attacker would do by a kind of trial and error (probably by a test run that has a whole slew of "%08x" formats until he can 'see' where the format string starts).

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

Anyway, when printf() gets to processing the "%s" format specifier, it has consumed all the stack entries up to where the outstring buffer resides. The "%s" specifier treats its stack entry as a pointer, and the string that the user has put into that buffer has been carefully crafted to have a binary representation of 0x08480110, so printf() will print out whatever is at that address as an ASCIIZ string.

这篇关于格式字符串漏洞 - printf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆