C语言输入安全10大边界漏洞解析与防御
在CVE漏洞数据库中,输入处理漏洞占比超过23%,其中边界问题是最主要的根源。本文将深入解析C语言输入处理的10种致命陷阱,并提供可落地的安全编码方案。
一、未限定长度的字符串复制
漏洞代码
char buf[64];
gets(buf); // 致命危险!
漏洞形成机制
-
栈内存结构:
| buffer[0-63] | EBP | 返回地址 | 参数... | ↑ ↑ ESP EBP
-
溢出过程:
- 输入超过63字符时,
\0
终止符被覆盖 - 继续写入会覆盖EBP和返回地址
- 攻击者精心构造的64-72字节可完全控制返回地址
- 输入超过63字符时,
-
利用技术:
# 攻击载荷构造 payload = (b"\x90"*40 + # NOP雪橇shellcode + # 恶意机器码b"A"*(64-40-len(shellcode)) # 填充struct.pack("<I", 0xffffd3a0) # 覆盖返回地址 )
防范原理
fgets()
的安全机制:
char* fgets(char* s, int size, FILE* stream) {int c;char* p = s;while (--size > 0 && (c = getc(stream)) != EOF) {*p++ = c;if (c == '\n') break; // 关键:遇到换行终止}*p = '\0'; // 确保终止符return (c == EOF && p == s) ? NULL : s;
}
二、strncpy未添加终止符
漏洞代码
char dest[32];
strncpy(dest, src, sizeof(dest)); // 可能无终止符
漏洞形成机制
-
内存布局示例:
dest: [d][a][t][a][...][?] // 无终止符 后续变量: [v][a][l][u][e] // 被当作字符串延续
-
信息泄露场景:
printf("Data: %s", dest); // 打印dest及后续内存
- 输出可能包含密码、密钥等敏感数据
-
崩溃原理:
- 无终止符的字符串操作会持续读取
- 直到遇到随机
\0
或触发页错误
防范原理
双重保障策略:
// 方案1:预置终止符
dest[sizeof(dest)-1] = '\0'