【问题标题】:Is printf unsafe to use in C在 C 中使用 printf 不安全吗
【发布时间】:2021-01-10 12:32:13
【问题描述】:

我是 C 的新手,所以我开始玩一些代码。我的代码中有一个错误,因为我认为使用 printf(pass) 不安全,因为它可以覆盖该值,因此对用户不安全。我想知道printf(pass) 在我的代码中是不安全的吗?另外,我怎样才能让用户在不更改代码的情况下打印消息finally logged in。有什么办法吗?

我的代码:

#include <stdio.h>

char pass[100];

char getPass() {
  int value = 'G';
  int * j = & value;
  fgets(pass, sizeof(pass), stdin);
  printf("your entered pass is ");
  printf(pass);
  return (char)( * j);
}

void main() {
  printf("enter the pass here ");
  if (getPass() == 'K') {
    printf("finally logged in\n");
    exit(0);
  } else {
    printf("Wrong password\n");
    exit(1);
  }
}

【问题讨论】:

  • “它可以覆盖值” - 什么值?你担心覆盖什么? printf 只写信给stdout 所以不清楚这里有什么不安全的地方
  • 你多次提到print。你的意思是printf?此外,如果您对其应用一些标准缩进,您的代码会更容易阅读。
  • @UnholySheep 我的意思是如果它覆盖任何用户键入的密码。用户也可以使用错误的密码登录。
  • @TomKarzes 抱歉,我已经缩进了我的代码。而且,是的,我的意思是 printf。我的意思是它是缓冲区溢出漏洞吗?
  • @Sky Right。这应该是显而易见的。如果密码是%s%d%p%x,会发生什么?你认为printf 会对这样的格式字符串做什么?它会寻找不存在的其他参数,因此它可能会出现段错误,或者它可能会拾取一些垃圾值然后扩展它们。它不会做的一件事是打印密码。

标签: c printf fgets c-strings


【解决方案1】:

如果函数fgets调用成功,它会提供一个可以输出的字符串。

如果这样输出得到的字符串会出现问题

printf(pass);

并包含转换指定。

所以不是那个电话

printf(pass);

使用起来更安全

printf( "%s", pass );

puts(pass);

初步可以通过fgets的调用删除字符串中存储的换行符。

【讨论】:

  • 我想知道是不是缓冲区溢出漏洞(这里的printf(pass)?这就是我所说的不安全。
  • @Sky 当您在 fgets sizeof(pass) 调用中明确指定数组的大小时,不会出现缓冲区溢出。
  • 另外,如何让用户打印“终于登录”?即使密码不正确或以某种方式覆盖某些内容,是否有可能?
  • 你的意思是即使在 printf(pass) 中也没有缓冲区溢出?
  • @Sky 没有缓冲区溢出。如果字符串包含转换说明符,则可能存在未定义的行为。
【解决方案2】:

是的,它不安全,但不是因为您建议的原因。如果您查看man 页面中的printf() 函数,您会看到它具有以下原型:

int printf(const char * restrict format, ...);

应用于第一个参数的const修饰符指定调用此函数时不会更改此参数的值。

但是,您还会注意到此参数称为format。那是因为它应该指定一个格式字符串。在您的程序中,没有什么可以阻止用户输入像%p 这样的格式说明符,在这种情况下,您对printf() 的调用将开始打印出堆栈的内容。有一个Wikipedia article 更详细地描述了这个漏洞。

【讨论】:

  • 我明白了。那么它是我代码中唯一的漏洞吗?另外,我怎样才能让用户以某种方式打印“终于登录”消息。有可能吗?
  • printf("finally logged in\n"); 最好编码为puts("finally logged in");,但不易受到攻击。问题出在printf(pass); 上,其中pass 是从用户输入中获得的。请改用printf("%s", pass);
  • 我明白了。但是,我的意思是有什么方法可以打印finally logged in而不更改我的代码,因为没有将其更改为puts()或任何东西,并使用该漏洞以某种方式输出finally logged in消息,因为它只会输出它等于k
  • 是的,有。阅读printf() 的文档。 %n 说明符存储到目前为止在指针指定的位置打印的字符数。如果用户输入了一个由 75 个字符组成的字符串,后跟 %n,那么您对 ​​printf() 的调用会将值 75(K 的 ASCII 代码)存储在堆栈指针的位置。稍加努力,就可以覆盖int value 的值。 (提示:尝试使用指针 j 做一些事情。)
  • 我尝试在 75 个字符后写 K 并继续这样做,但没有成功。例如,我在第 76 位、第 77 位等写了 K,但它并没有覆盖该值。能否请你帮忙?我一直试图弄清楚你所说的,甚至阅读了自过去几个小时以来我仍然被困住的文档
猜你喜欢
  • 2022-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-31
  • 2017-08-16
  • 1970-01-01
相关资源
最近更新 更多