使用printf / scanf和%s的漏洞

时间:2016-03-01 22:31:55

标签: c printf scanf

为什么即使我尝试提供正确的输入,C也告诉我这是不安全的?

#include <stdio.h> 
#include <stdlib.h>

int main(void) {
    char id[8];

    printf("Your ID:");
    scanf("%s", id);

    printf("%s", id);

    return 0; 
}

我假设是因为它可以被利用?怎么样?

3 个答案:

答案 0 :(得分:3)

scanf()没有设置输入所需的任何界限,因此很容易使id[]缓冲区溢出。

现代编译器可能会启用堆栈粉碎检测,因此如果您通过gcc进行编译而不设置-fno-stack-protector标志,程序将故意提前崩溃,而不是运行这样一个讨厌的错误而不是注意到。

您最好使用fgets()然后使用sscanf()或其他一些机制来解析输入,这样您就可以保证丢弃额外的输入。

答案 1 :(得分:2)

id是8个字符长的缓冲区。 scanf("%s", id);未检查输入字符串的长度。因此,如果用户输入长度超过7个字符的字符串(空终止符为+1),它将溢出分配的缓冲区并中断程序。如果字符串是以特殊方式制作的,则可能允许黑客获得一些权限,例如执行任意代码。

答案 2 :(得分:2)

除了过度运行id[]数据太多外,还有另一个漏洞:
不检查输入功能的返回值。

用户可以关闭stdin,导致scanf("%s", id)返回EOF,而不会在id[]中放置任何内容。然后,以下printf("%s", id);尝试打印未初始化的缓冲区。

char id[8];
scanf("%s", id);  // Bad, return value not checked.
printf("%s", id);

// Better
if (1 == scanf("%7s", id)) {
  printf("%s", id);
}

// even better
if (fgets(id, sizeof id, stdin)) {
  id[strcspn(id, "\n")] = '\0'; // lop off potential \n
  printf("%s", id);
}