NNTS.MUST
非 Null 结尾的字符串导致的缓冲区溢出
在 C 和 C++ 中,C 字符串或 Null 结尾的字符串是以空字符 (\0) 结尾的字符序列。C 字符串的长度通过搜索空字符来确定。
NNTS 系列检查器会查找那些使用了带有并非或可能并非以 Null 终止的字符数组的字符串操纵函数的代码。NNTS.MUST 检查器查找使用字符串操纵函数的代码,其中的字符数组并非以 Null 结尾。
漏洞与风险
Null 结尾曾经导致过安全性问题。例如:
- 在字符串中插入空字符可能导致意外地将其截断
- 没有为空字符分配足够的空间或忘记空字符的存在是很常见的 bug
- 许多程序在将字符串复制到固定大小的缓冲区之前都不会检查长度,当字符串太长时,就会导致缓冲区溢出
- 无法保存空字符就意味着字符串和二进制数据需要由不同的函数来处理,如果使用了错误的函数就可能导致问题
缓解与预防
为了避免问题:
- 如果性能约束条件允许,可添加特殊的代码来验证字符串缓冲区是否以 Null 结尾
- 切换到有界字符串操纵函数,比如 strncpy
- 检查缓冲区溢出引用通告中所涉及的缓冲区长度
漏洞代码示例
复制
#include <stdio.h>
int main()
{
char buf[8];
char tgt[1024];
const char * src = "abcdef";
strncpy(buf, src, 3);
strcpy(tgt, buf);
return 0;
}
Klocwork 针对数组 tgt 第 10 行生成缓冲区溢出报告:因非 Null 结尾的字符串 buf 导致 tgt 缓冲区溢出。针对第 10 行的数组 buf 报告了类似错误。在本示例中,报告了两次数组边界违规,因为读取了 buf 并写入了 tgt。读取和写入都超出了缓冲区的边界(等于或大于 3),其原因是 buf 并非以 Null 结尾(不正确使用 strcpy 将反过来导致此结果)。该代码将导致缓冲区溢出,并造成各种严重的问题。
外部指导
- CERT ARR00-C:了解数组的工作原理
- CERT ARR30-C:不形成或使用超出边界的指针或数组下标
- CERT STR03-C:请勿无意中截断字符串
- CERT STR32-C:请勿将非 Null 结尾的字符序列传递给需要字符串的库函数
- CERT STR50-CPP:确保字符串存储器具有足够的空间存储字符数据和 Null 终止符
- CWE-20:不正确的输入验证
- CWE-119:未正确地将操作限制在内存缓冲区边界内
- CWE-125:超出边界的读取
- CWE-170:不正确的 Null 结尾
- CWE-787:超出边界的写入
- OWASP A3:2021 注入
- STIG-ID:APP3590.1 应用程序易受缓冲区溢出影响
扩展
此检查器可进行扩展。有关详情,请参阅调整 C/C++ 分析。