ID: 805 类型:基础 | 状态:未完成 |
描述
软件使用顺序操作来读取或写入缓冲区,但它使用的长度值不正确,导致它访问超出缓冲区界限的内存。
扩展描述
当长度值超过目标的大小时,可能发生缓冲区溢出。
相关视图
“研究概念”视图(CWE-1000)
Nature | Type | ID | Name |
ChildOf | 119 | Improper Restriction of Operations within the Bounds of a Memory Buffer | |
ParentOf | 806 | ||
CanFollow | 130 |
“开发概念”视图 (CWE-699)
Nature | Type | ID | Name |
ChildOf | 119 | Improper Restriction of Operations within the Bounds of a Memory Buffer | |
ParentOf | 806 |
引入模式
阶段 | 说明 |
实现 |
应用平台
语言
C (经常出现)
C++ (经常出现)
Class: Assembly (出现的可能性不确定)
后果
范围 | 冲击 | 可能性 |
完整性 | 技术冲击: 执行未获授权的代码或命令 缓冲区溢出通常可用于执行任意代码,这通常不在程序的安全策略的范围内。这通常可用于颠覆任何其他安全服务。 | |
可利用性 | 技术冲击: DoS: 崩溃、推出或者重启: DoS: 资源消耗 (CPU) 缓冲区溢出通常会导致崩溃。其他导致可用性不足的攻击是可能的,包括将程序放入无限循环。 |
被利用的可能性:
高
示例
例1
此示例从用户获取IP地址,验证其格式是否正确,然后查找主机名并将其复制到缓冲区中。
(问题代码)
Example Language: C
void host_lookup(char *user_supplied_addr){
struct hostent *hp;
in_addr_t *addr;
char hostname[64];
in_addr_t inet_addr(const char *cp);
/*routine that ensures user_supplied_addr is in the right format for conversion */
validate_addr_form(user_supplied_addr);
addr = inet_addr(user_supplied_addr);
hp = gethostbyaddr( addr, sizeof(struct in_addr), AF_INET);
strcpy(hostname, hp->h_name);
}
此函数在假定主机名的最大长度值为64字节的情况下,为存储主机名分配64字节的缓冲区,但不能保证主机名不会大于64字节。如果攻击者指定的地址解析为非常大的主机名,那么我们可能会覆盖敏感数据,甚至将控制流放弃给攻击者。
请注意,此示例还包含一个未选中的返回值(CWE-252),它可能导致空指针取消引用(CWE-476)。
例2
在下面的示例中,可以请求memcpy移动比假定的内存段大得多的内存段:
(问题代码)
Example Language: C
int returnChunkSize(void *) {
/* if chunk info is valid, return the size of usable memory,
* else, return -1 to indicate an error
*/
...
}
int main() {
...
memcpy(destBuf, srcBuf, (returnChunkSize(destBuf)-1));
...
}
如果returnChunkSize()遇到错误,它将返回-1。请注意,在memcpy操作(cwe-252)之前不会检查返回值,因此-1可以作为size参数传递给memcpy()(cwe-805)。因为memcpy()假定该值是无符号的,所以它将被解释为maxint-1(cwe-195),因此将复制比目标缓冲区(cwe-787、cwe-788)可能可用的内存多得多的内存。
例3
在下面的示例中,使用strncpy方法将源字符串复制到dest字符串。
(问题代码)
Example Language: C
...
char source[21] = "the character string";
char dest[12];
strncpy(dest, source, sizeof(source)-1);
...
但是,在对strncpy的调用中,在sizeof调用中使用源字符串来确定要复制的字符数。这将创建缓冲区溢出,因为源字符串的大小大于dest字符串。应在sizeof调用中使用dest字符串,以确保复制正确的字符数,如下所示。
(正确代码)
Example Language: C
...
char source[21] = "the character string";
char dest[12];
strncpy(dest, source, sizeof(dest)-1);
...
例4
在本例中,方法outputfilenametolog将文件名输出到日志文件。方法参数包括指向包含文件名的字符串的指针和字符串中字符数的整数。将文件名复制到一个缓冲区,其中缓冲区大小设置为日志文件输入的最大大小。然后,该方法调用另一个方法将缓冲区的内容保存到日志文件中。
(问题代码)
Example Language: C
#define LOG_INPUT_SIZE 40
// saves the file name to a log file
int outputFilenameToLog(char *filename, int length) {
int success;
// buffer with size set to maximum size for input to log file
char buf[LOG_INPUT_SIZE];
// copy filename to buffer
strncpy(buf, filename, length);
// save to log file
success = saveToLogFile(buf);
return success;
}
但是,在这种情况下,字符串复制方法strncpy错误地使用length方法参数来确定要复制的字符数,而不是使用本地字符串buf的大小。如果文件名指向的字符串中包含的字符数大于本地字符串允许的字符数,则可能导致缓冲区溢出。字符串复制方法应该在size of调用中使用buf字符串,以确保只复制buf数组大小以下的字符以避免缓冲区溢出,如下所示
(正确代码)
Example Language: C
...
// copy filename to buffer
strncpy(buf, filename, sizeof(buf)-1);
...
应对措施
阶段: 需求 策略: 语言选择 使用不允许出现这种弱点的语言,或提供使这种弱点更容易避免的结构。 例如,许多执行自己的内存管理的Java(如Java和Perl)不受缓冲区溢出的影响。其他语言,如ada和c,通常提供溢出保护,但程序员可以禁用该保护。 请注意,即使语言本身在理论上是安全的,语言与本机代码的接口仍然可能受到溢出的影响。 |
阶段: 架构与设计 策略: 库或者框架 使用一个经过审查的库或框架,它不允许出现这种弱点,或者提供使这种弱点更容易避免的结构。 示例包括Messier和Viega[Ref-57]的safe c字符串库(safestr)和Microsoft的strsafe.h库[Ref-56]。这些库提供了更安全的易于溢出的字符串处理函数版本。 注意:这不是一个完整的解决方案,因为许多缓冲区溢出与字符串无关。 |
阶段: 编译及链接 策略: 强化编译与链接 使用自动提供保护机制的功能或扩展运行或编译软件,以减轻或消除缓冲区溢出。 例如,某些编译器和扩展提供了内置于编译代码中的自动缓冲区溢出检测机制。示例包括Microsoft Visual Studio/GS标志、Fedora/Red Hat强化源代码gcc标志、StackGuard和Propolice。 有效性: 深度防御 说明: 这不一定是一个完整的解决方案,因为这些机制只能检测某些类型的溢出。此外,攻击仍然可能导致拒绝服务,因为典型的响应是退出应用程序。 |
阶段:实现
|
阶段: 架构与设计 对于在客户端执行的任何安全检查,请确保这些检查在服务器端重复,以避免CWE-602。攻击者可以通过在执行检查后修改值或更改客户端以完全删除客户端检查来绕过客户端检查。然后,将这些修改后的值提交给服务器。 |
阶段: 操作 策略: 强化环境 使用随机排列程序可执行文件和库在内存中的位置的特性或扩展来运行或编译软件。因为这会使地址不可预测,所以可以防止攻击者可靠地跳到可利用的代码上。 示例包括地址空间布局随机化(ASLR)[Ref-58][Ref-60]和位置独立可执行文件(Pie)[Ref-64]。 有效性: 深度防御 注意:这不是一个完整的解决方案。然而,它迫使攻击者猜测一个未知值,该值会改变每个程序的执行。此外,攻击仍然可能导致拒绝服务,因为典型的响应是退出应用程序。 |
阶段: 操作 策略: 强化环境 使用提供数据执行保护(NX)或其等效设备的CPU和操作系统[Ref-59][Ref-57]。有效性: 深度防御 注意:这不是一个完整的解决方案,因为缓冲区溢出可以用来覆盖附近的变量,以危险的方式修改软件的状态。此外,它不能用于需要自我修改代码的情况。最后,攻击仍然可能导致拒绝服务,因为典型的响应是退出应用程序。 |
阶段: 架构与设计; 操作 策略: 强化环境 使用完成必要任务所需的最低权限运行代码[Ref-76]。如果可能,请创建仅用于单个任务的具有有限权限的独立帐户。这样,成功的攻击不会立即让攻击者访问软件的其余部分或其环境。例如,数据库应用程序很少需要以数据库管理员的身份运行,特别是在日常操作中。 |
Phases: 架构与设计; 操作 策略: 沙箱或牢房 在“监狱”或类似的沙盒环境中运行代码,该环境强制在进程和操作系统之间建立严格的边界。这可能有效地限制哪些文件可以在特定目录中访问,或者哪些命令可以由软件执行。 操作系统级的例子包括unix chrot-guille、apparmor和selinux。一般来说,托管代码可能提供一些保护。例如,java中的子查询允许软件指定对文件操作的限制。 这可能不是一个可行的解决方案,它只限制了对操作系统的影响;应用程序的其余部分仍然可能受到损害。 小心避免与监狱有关的CWE-243和其他弱点。 有效性: 有限 注意:此缓解措施的有效性取决于所使用的特定沙箱或坚固房的预防能力,可能只有助于减少攻击范围,例如限制攻击者进行某些系统调用或限制可访问的文件系统部分。 |
种属
关系 | 类型 | ID | 名称 |
属于 | 740 | CERT C Secure Coding Standard (2008) Chapter 7 - Arrays (ARR) | |
属于 | 802 | ||
属于 | 867 | ||
属于 | 874 | CERT C++ Secure Coding Section 06 - Arrays and the STL (ARR) | |
属于 | 884 | ||
属于 | 1160 |