为什么这个代码是可被利用的?
问题描述:
为什么这段代码是不安全的?为什么这个代码是可被利用的?
#include <stdio.h>
int main(int argc, char *argv[])
{
printf(argv[1]);
printf("\n");
return 0;
}
答
printf
将处理它的第一个参数,寻找的东西像%d
和%s
。
基于这些值,它将从堆栈中获取更多数据并将其打印出来。
所以,如果有人叫你的程序:
a.out "%d %d %d %d %d %d %d %d %d %d %d %d"
他们可以查看您的计算机的调用堆栈的一部分。
如果他们对格式说明符有更多的创造性,他们可能会转储一些重要的东西,比如信用卡号码或密码。
答
考虑一下的printf
控制的第一个参数(提示:printf
不只是读它的输入参数)。
答
由于海报问一个例子是什么呢%n
:
的方式printf
格式字符串可以变化内存是使用%n
选项;通过“明智地”使用格式宽度说明符可以获得要写入的特定值。作为一个测试:
#include <stdio.h>
int main(int argc, char **argv)
{
int *q = (int *)argv[0];
printf("%1$300000d%5$n",
123, // %1 - 1st param (formatted as '300000d')
0, // %2 - 2nd param (unused)
0, // %3 - 3rd param (unused)
0, // %4 - 4th param (unused)
argv[0]); // %5 - 5th param (written to via 'n')
printf("\nNow *q == %d\n", *q);
return 0;
}
如果你运行这个,看看输出的最后一行,它会打印Now *q == 300000
(在Linux上测试)。
我使用printf()
这里的,而未知位置格式的语法(%
<POS> $
<FMT>),以显示如何能够跳过参数选择修改哪一个,而无需使用任何的“无趣”的。
我会让读者进行实验来找出printf()
作为printf(argv[1])
这样的调用的“参数”。答案取决于您的系统的calling conventions(或相关,ABI),并且对于32/64位Windows/Linux/MacOSX等不同。
为什么我们应该为您做作业? – 2012-04-09 21:12:42
http://en.wikipedia.org/wiki/Uncontrolled_format_string – 2012-04-09 21:13:04