样例 1
#include <stdio.h>
#include <string.h>
#define MAX_SIZE 256
void safe_function(char *input) {
char buffer[MAX_SIZE];
// 使用strncpy防止溢出
strncpy(buffer, input, sizeof(buffer));
printf("Received: %s\n", buffer);
}
int main() {
char input[] = "This is a test string that should not exceed the maximum size.";
safe_function(input);
return 0;
}
strncpy
不会自动在目标缓冲区末尾添加空终止符(\0
)。如果输入字符串长度等于或超过 buffer
的大小(MAX_SIZE
),buffer
将不是一个合法的 C 字符串,后续操作(如 printf
)可能导致内存越界读取或程序崩溃。
修复的话就手动添加终止符(或者直接用 strncpy 的填充 0)
strncpy(buffer, input, sizeof(buffer) - 1);
样例 2
#include <stdio.h>
#include <string.h>
void vulnerable_function() {
char buffer[64];
printf("Input: ");
gets(buffer);
printf("You entered: %s\n", buffer);
}
int main() {
setvbuf(stdout, NULL, _IONBF, 0);
vulnerable_function();
return 0;
}
gets
函数不检查输入长度,当输入超过 buffer
的容量(64 字节)时,会导致缓冲区溢出,覆盖栈上的关键数据(如返回地址),可以任意代码执行。
可以使用安全的输入函数
fgets(buffer, sizeof(buffer), stdin);
样例 3
#include <stdio.h>
#include <string.h>
void success(void) { puts("You Hava already controlled it."); }
void vulnerable(void) {
char s[12];
gets(s);
puts(s);
return;
}
int main(int argc, char **argv) {
vulnerable();
return 0;
}
gets
未限制输入长度,输入超过 12 字节会溢出 s
数组。可覆盖栈上的返回地址,劫持程序流程(如跳转至 success
函数)
修复也是修改为更加安全的函数
fgets(s, sizeof(s), stdin);
这里局部变量没有初始化,不过 fgets 函数只会读取 n-1 个字符(如果遇到换行符会更少),并在最后添加字符串结束标志,所以直接这么改就行了