如何解决在scanf之后使用printf时的异常行为
我正在使用scanf()
从用户那里获取密码,并将其存储在大小为20个字节的password
变量中。我对照correctPassword
检查输入的密码,如果它们匹配,则布尔变量pass
将更改为true
。
因此,当我输入长度超过20个字符的密码时,将发生缓冲区溢出,并且pass
的值将变为非零(即true)。但是,当我使用printf()
打印变量pass
的地址时,即使我使用的密码长度超过20个字符,也不会发生缓冲区溢出。
这是导致溢出的代码:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
int main (int argc,char *argv[]) {
char password[20];
char correctPassword[] = "random";
bool pass = false;
printf("enter your password: ");
scanf("%s",password);
if (strcmp(password,correctPassword) == 0) {
// compare the two strings,strcmp() returns 0 if two strings values are the same.
pass = true;
}
if (pass) {
printf("Connecting you to the central system...\n");
} else {
printf("Password is wrong! entry denied\n");
}
printf("%d\n",pass);
return 0;
}
在这种情况下,输入的密码长度为40个字符(a
的ASCII值为97)时,pass的值将更改为97(true)。
enter your password: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Connecting you to the central system...
97
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
int main (int argc,char *argv[]) {
char password[20];
char correctPassword[] = "random";
bool pass = false;
printf("enter your password: ");
scanf("%s",strcmp() returns 0 if two strings values are the same.
pass = true;
}
if (pass) {
printf("Connecting you to the central system...\n");
} else {
printf("Password is wrong! entry denied\n");
}
printf("%d\n",pass);
printf("%x\n",&pass);
return 0;
}
在这种情况下,输入的密码长40个字符,但是pass
仍然是0
(假)。
enter your password: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Password is wrong! entry denied
0
61fec4
所以,我的问题是怎么只添加
printf("%x\n",&pass);
导致没有缓冲区溢出?
解决方法
scanf("%s",password)
是一个安全漏洞:长度超过19个字节的任何输入字都将导致scanf()
超出数组末尾写入,从而触发未定义的行为。
未定义的行为可能会带来无法预料的副作用,无论是否可见。 97
的输出是一个轻微的副作用,但是足够长的输入将破坏返回地址并在从main()
返回时导致分段错误,并且巧妙构造的输入可能使攻击者可以执行任意代码。更改程序可能会改变副作用,因为局部变量的分配可能会有所不同,例如当您使用&pass
的地址时。这些都不是可预见的。
还请注意,printf("%x\n",&pass);
也具有未定义的行为,因为%x
期望使用unsigned int
而不是bool *
,因此您应该写printf("%p\n",(void *)&pass);
有一种简单的方法可以通过将长度字段传递给scanf()
来防止这种情况:
scanf("%19s",password);
但是请注意,您还应该检查返回值以检测文件的过早结束,并且还应该刷新输入行的其余部分。
这是修改后的版本:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc,char *argv[]) {
char password[20];
char correctPassword[] = "random";
bool pass = false;
int c;
printf("enter your password: ");
if (scanf("%19s",password) != 1) {
printf("invalid input\n");
return 1;
}
/* read and discard the rest of the line */
while ((c = getchar()) != EOF && c != '\n')
continue;
if (strcmp(password,correctPassword) == 0) {
// compare the two strings,strcmp() returns 0 if two strings values are the same.
pass = true;
}
if (pass) {
printf("Connecting you to the central system...\n");
} else {
printf("Password is wrong! entry denied\n");
}
printf("%d\n",pass);
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。