以下是一个玩具程序,可以抑制缓冲区溢出漏洞:
#include < stdio.h >
#include < string.h >
/* Returns 1 if pass is
* the correct password, otherwise 0 */
int check_correct_passwd(char * pass) {
/* Omitted */
/* Very complex logic */
return 0;
}
void print_secret_key() {
int c;
FILE * file;
file = fopen("/home/alice/master-secret.txt", "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
} else {
printf("Failed to open master-secret.txt");
}
}
int main(int argc, char ** argv) {
int decision;
char passwd[16];
if (argc < 2) {
printf("usage: %s password\n", argv[0]);
return 0;
}
decision = check_correct_passwd(argv[1]);
strcpy(passwd, argv[1]);
printf("%d\n", decision);
printf("%s\n", argv[1]);
if (decision) {
printf("Access granted to the document with passwd %s!\n", passwd);
print_secret_key();
} else
printf("Access denied.\n");
return 0;
}
操作系统为Linux 4.14.76
。编译器版本为gcc 8.2.1
。
我正在使用gcc getkey.c -ggdb -fno-stack-protector -o getkey
编译该程序,基本上放置了调试符号并禁用了堆栈金丝雀。
我希望该程序在接收到长度大于16的输入时打印出主密钥,因为它将覆盖决策并迫使分支评估为true。但是,所需的长度远大于16。GDB显示这些变量的地址,以及执行strcpy(passwd, argv[1])
之后的内容,如下所示:
(gdb) print &passwd
$17 = (char (*)[16]) 0x7fffffffe0b0
(gdb) print &decision
$18 = (int *) 0x7fffffffe0cc
(gdb) x/16b &passwd
0x7fffffffe0b0: "01234567890123456"
0x7fffffffe0c2: "\377\377\377\177"
0x7fffffffe0c7: ""
0x7fffffffe0c8: ""
0x7fffffffe0c9: ""
0x7fffffffe0ca: ""
0x7fffffffe0cb: ""
0x7fffffffe0cc: ""
0x7fffffffe0cd: ""
0x7fffffffe0ce: ""
0x7fffffffe0cf: ""
0x7fffffffe0d0: "\360RUUUU"
0x7fffffffe0d7: ""
0x7fffffffe0d8: "#\322\337\367\377\177"
0x7fffffffe0df: ""
0x7fffffffe0e0: ""
passwd
和decision
之间的内存间隔为0x1c
= 28个字节。还有12个字节,我无法解释它们的存在。这么长的差距有什么解释?