NNTS.TAINTED
受污染输入中的非 Null 结尾字符串导致的缓冲区溢出
在 C 和 C++ 中,C 字符串或 Null 结尾的字符串是以空字符 (\0) 结尾的字符序列。C 字符串的长度通过搜索空字符来确定。
NNTS 系列检查器会查找那些使用了带有并非或可能并非以 Null 终止的字符数组的字符串操纵函数的代码。NNTS.TAINTED 检查器会查找因非 Null 结尾字符串所导致的缓冲区溢出,这些字符串的来源可能是用户或外部设备输入的未经验证或已受污染的数据。此检查器会通过代码标记执行路径,在该代码中,缓冲区溢出中涉及的输入数据未进行验证。
漏洞与风险
Null 结尾曾经导致过安全性问题。例如:
- 在字符串中插入空字符可能导致意外地将其截断
- 没有为空字符分配足够的空间或忘记空字符的存在是很常见的 bug
- 许多程序在将字符串复制到固定大小的缓冲区之前都不会检查长度,当字符串太长时,就会导致缓冲区溢出
- 无法保存空字符就意味着字符串和二进制数据需要由不同的函数来处理,如果使用了错误的函数就可能导致问题
缓解与预防
为了避免问题:
- 如果性能约束条件允许,可添加特殊的代码来验证字符串缓冲区是否以 Null 结尾
- 切换到有界字符串操纵函数,比如 strncpy
- 检查缓冲区溢出引用通告中所涉及的缓冲区长度
漏洞代码示例
复制
void TaintedAccess()
{
char src[32];
char dst[48];
read(0, src, sizeof(src));
strcpy(dst, src);
}
函数 read 从外部来源(文件)中读取任意数据,而它可能已被污染。所得的缓冲区无法保证以 Null 结尾(在此缓冲区的静态大小没有影响)。当调用 strcpy 时,发生两处违规:读取超出 src 的限制,写入超出 dst 的限制。在本例中,NNTS.TAINTED 检查器查找到了两处因非 Null 结尾字符串所导致的缓冲区溢出,这些字符串的来源可能是用户或外部设备输入的、未经验证的数据。Klocwork 针对数组 dst 第 8 行生成缓冲区溢出报告:dst 缓冲区溢出,原因是未经验证的用户输入中包含非 Null 结尾的字符串 src。在第 8 行也针对数组 src 报告了类似错误。该代码将导致缓冲区溢出,并造成各种严重的问题。
外部指导
- CERT ARR00-C:了解数组的工作原理
- CERT ARR30-C:不形成或使用超出边界的指针或数组下标
- CERT STR02-C:整理传递至复杂子系统的数据
- CERT STR50-CPP:确保字符串存储器具有足够的空间存储字符数据和 Null 终止符
- CWE-20:不正确的输入验证
- CWE-119:未正确地将操作限制在内存缓冲区边界内
- CWE-125:超出边界的读取
- CWE-170:不正确的 Null 结尾
- CWE-787:超出边界的写入
- CWE-896:无
- OWASP A3:2021 注入
- STIG-ID:APP3510 输入验证
- STIG-ID:APP3570 易受命令注入影响的应用程序
- STIG-ID:APP3590.1 应用程序易受缓冲区溢出影响
扩展
此检查器可进行扩展。通过 Klocwork 知识库可添加特定于平台和特定于应用程序的信息。配置信息用于描述执行缓冲区操作的系统功能的属性。在标准发行版中,提供了多个特定于平台的配置。有关详情,请参阅调整 C/C++ 分析。