【问题标题】:Vulnerability using printf/scanf and %s使用 printf/scanf 和 %s 的漏洞
【发布时间】:2016-06-14 13:55:36
【问题描述】:

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

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

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

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

    printf("%s", id);

    return 0; 
}

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

【问题讨论】:

  • 互联网搜索不起作用吗?
  • 如果我输入一个 50 个字符的字符串会怎样?你只有一个 8 字节的缓冲区。
  • 如果有人输入超过 8 个字符,它会覆盖内存,可能带来灾难性的后果。
  • 使用char id[8],您分配了固定数量的内存,但scanf 不知道。
  • 谢谢大家,我明白了。我应该环顾四周!

标签: c printf scanf


【解决方案1】:

scanf() 没有对它作为输入的内容设置任何界限,因此很容易溢出id[] 缓冲区。

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      除了用太多数据过度运行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);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-18
        • 1970-01-01
        • 1970-01-01
        • 2019-11-06
        • 1970-01-01
        • 1970-01-01
        • 2017-01-17
        • 2021-11-26
        相关资源
        最近更新 更多