ID: 131 类型:基础 | 状态:草稿 |
描述
软件无法正确计算分配缓冲区时要使用的大小,这可能导致缓冲区溢出。
相关视图
与“研究层面”视图(CWE-1000)相关
与“开发层面”视图(CWE-699)相关
引入模式
阶段 | 说明 |
实现 |
应用平台
语言
C (出现的可能性不确定)
C++ (出现的可能性不确定)
后果
范围 | 冲击 | 可能性 |
完整性 | 技术冲击: DoS: 崩溃、推出或者重启: 执行未获授权的代码或命令; Read Memory; 修改内存 如果在内存分配的上下文中使用了不正确的计算,那么软件可能会创建一个小于或大于预期的缓冲区。如果分配的缓冲区小于预期值,这可能导致读取或写入越界(CWE-119),可能导致崩溃、允许任意代码执行或公开敏感数据。 |
被利用的可能性:
高
示例
例1
以下代码为最大数量的小部件分配内存。然后它得到用户指定数量的小部件,确保用户不会请求太多。然后,它使用initializeWidget()初始化数组元素。因为每个请求的小部件数量可能不同,所以代码插入一个空指针来表示最后一个小部件的位置。
(问题代码)
Example Language: C
int i;
unsigned int numWidgets;
Widget **WidgetList;
numWidgets = GetUntrustedSizeValue();
if ((numWidgets == 0) || (numWidgets > MAX_NUM_WIDGETS)) {
ExitError("Incorrect number of widgets requested!");
}
WidgetList = (Widget **)malloc(numWidgets * sizeof(Widget *));
printf("WidgetList ptr=%p\n", WidgetList);
for(i=0; i<numWidgets; i++) {
WidgetList[i] = InitializeWidget();
}
WidgetList[numWidgets] = NULL;
showWidgets(WidgetList);
但是,此代码包含逐次计算错误。它精确地分配足够的空间来包含指定数量的小部件,但不包括空指针的空间。因此,分配的缓冲区比预期的要小。因此,如果用户请求max_num_小部件,则在分配空值时会出现一个“关闭一次”缓冲区溢出(CWE-193)。根据环境和编译设置,这可能导致内存损坏。
例2
以下图像处理代码为图像分配表。
(问题代码)
Example Language: C
img_t table_ptr; /*struct containing img data, 10kB each*/
int num_imgs;
...
num_imgs = get_num_imgs();
table_ptr = (img_t*)malloc(sizeof(img_t)*num_imgs);
...
此代码打算分配一个大小为num_imgs的表,但是随着num_imgs变大,确定列表大小的计算最终将溢出(CWE-190)。这将导致分配的列表非常小。如果后续代码对列表进行操作,就像它是num-imgs long一样,那么可能会导致许多类型的越界问题(CWE-119)。
例3
此示例将编码过程应用于输入字符串,并将其存储到缓冲区中
(问题代码)
Example Language: C
char * copy_input(char *user_supplied_string){
int i, dst_index;
char *dst_buf = (char*)malloc(4*sizeof(char) * MAX_SIZE);
if ( MAX_SIZE <= strlen(user_supplied_string) ){
die("user string too long, die evil hacker!");
}
dst_index = 0;
for ( i = 0; i < strlen(user_supplied_string); i++ ){
if( '&' == user_supplied_string[i] ){
dst_buf[dst_index++] = '&';
dst_buf[dst_index++] = 'a';
dst_buf[dst_index++] = 'm';
dst_buf[dst_index++] = 'p';
dst_buf[dst_index++] = ';';
}
else if ('<' == user_supplied_string[i] ){
/* encode to < */
}
else dst_buf[dst_index++] = user_supplied_string[i];
}
return dst_buf;
}
程序员试图对用户控制的字符串中的符号和字符进行编码,但是在应用编码过程之前,会验证字符串的长度。此外,程序员假定编码扩展只将给定字符扩展4倍,而与号的编码扩展5倍。因此,当编码过程扩展字符串时,如果攻击者提供一个包含多个符号的字符串,则可能溢出目标缓冲区。
例4
以下代码用于从套接字读取传入数据包并提取一个或多个头。
(问题代码)
Example Language: C
DataPacket *packet;
int numHeaders;
PacketHeader *headers;
sock=AcceptSocketConnection();
ReadPacket(packet, sock);
numHeaders =packet->headers;
if (numHeaders > 100) {
ExitError("too many headers!");
}
headers = malloc(numHeaders * sizeof(PacketHeader);
ParsePacketHeaders(packet, headers);
代码执行检查以确保数据包不包含太多的头。但是,numHeaders被定义为带符号的int,因此它可能是负数。如果传入数据包指定了一个值,例如-3,那么malloc计算将生成一个负数(如果每个头最多可以有100个字节,则为-300)。当将此结果提供给malloc()时,首先将其转换为大小类型。然后,该转换会产生一个较大的值,如4294966996,这可能会导致malloc()失败或分配非常大的内存量(CWE-195)。有了适当的负数,攻击者可以诱骗malloc()使用非常小的正数,然后分配比预期小得多的缓冲区,这可能导致缓冲区溢出。
例5
以下代码试图将三个不同的标识号保存到一个数组中。使用对malloc()的调用从内存分配数组。
(问题代码)
Example Language: C
int *id_sequence;
/* Allocate space for an array of three ids. */
id_sequence = (int*) malloc(3);
if (id_sequence == NULL) exit(1);
/* Populate the id array. */
id_sequence[0] = 13579;
id_sequence[1] = 24680;
id_sequence[2] = 97531;
上面代码的问题是malloc()调用期间使用的大小参数的值。它使用值“3”,根据定义,该值将产生三个字节的缓冲区。然而,其目的是创建一个包含三个整数的缓冲区,在C语言中,每个整数需要4个字节的内存,因此需要12个字节的数组,每个整数需要4个字节。执行上述代码可能会导致缓冲区溢出,因为12个字节的数据被保存到3个字节的已分配空间中。溢出将在分配id_序列[0]期间发生,并将继续分配id_序列[1]和id_序列[2]。
malloc()调用可以使用“3*size of(int)”作为size参数的值,以便分配存储这三个int所需的正确空间量。
应对措施
阶段: 实现 为转换、转化或编码输入而分配缓冲区时,分配足够的内存来处理最大可能的编码。例如,在将“&”字符转换为“&;”的例程中,对于HTML实体编码,输出缓冲区的大小至少需要是输入缓冲区的5倍。 |
阶段: 实现 了解编程语言的底层表示,以及它如何与数值计算(CWE-681)交互。密切关注字节大小差异、精度、有符号/无符号区别、截断、类型之间的转换和转换、“非数字”计算,以及语言如何处理对其基础表示而言太大或太小的数字。[RIF-7] 还要注意考虑32位、64位和其他可能影响数字表示的潜在差异。 |
阶段: 实现 策略: 验证输入 通过确保任何数字输入在预期范围内,对其执行验证输入。强制输入满足预期范围的最小和最大要求。 |
阶段: 架构与设计 对于在客户端执行的任何安全检查,请确保这些检查在服务器端重复,以避免CWE-602。攻击者可以通过在执行检查后修改值或更改客户端以完全删除客户端检查来绕过客户端检查。然后,这些修改后的值将提交给服务器。 |
阶段: 实现 在处理包含大小字段和原始数据的结构化输入数据时,识别并解决大小字段和数据实际大小(CWE-130)之间的任何不一致。 |
阶段: 实现 在分配使用哨兵标记数据结构结束的内存时(如字符串中的nul字节),请确保在计算必须分配的内存总量时也包含sentinel。 |
阶段: 实现 用支持长度参数的类似函数(如strcpy和strncpy)替换无边界复制函数。如果它们不可用,则创建它们。 有效性: 中等 注意: 这种方法仍然容易受到计算错误的影响,包括诸如逐点错误(CWE-193)和错误计算缓冲区长度(CWE-131)等问题。此外,这只解决潜在的溢出问题。资源消耗/消耗问题仍然存在。 |
阶段: 实现 在适当的数据类型上使用sizeof()以避免CWE-467。 |
阶段: 实现 为所需操作使用适当的类型。例如,在C/C++中,只使用无符号类型的值,这些值永远不会是负值,例如高度、宽度或与数量相关的其他数字。这将简化健全性检查,并将减少意外铸造的惊喜。 |
阶段: 架构与设计 策略: 库或者框架 使用一个经过审查的库或框架,它不允许出现这种弱点,或者提供使这种弱点更容易避免的结构。
使用使处理数字更容易而不会产生意外结果的框架,或自动跟踪缓冲区大小的缓冲区分配例程。 示例包括安全的整数处理包,如SafeInt(C++)或IntegerLib(C或C++)。[RIF-106] |
阶段: 编译及链接 策略: 强化编译与链接 使用自动提供保护机制的功能或扩展运行或编译软件,以减轻或消除缓冲区溢出。 例如,某些编译器和扩展提供了内置于编译代码中的自动缓冲区溢出检测机制。示例包括Microsoft Visual Studio/GS标志、Fedora/Red Hat强化源代码gcc标志、StackGuard和Propolice。 有效性: 深度防御 注意: 这不一定是一个完整的解决方案,因为这些机制只能检测某些类型的溢出。此外,攻击仍然可能导致拒绝服务,因为典型的响应是退出应用程序。 |
阶段: 操作 策略: 强化环境 使用随机排列程序可执行文件和库在内存中的位置的特性或扩展来运行或编译软件。因为这使得地址不可预测,所以可以防止攻击者可靠地跳到可利用的代码上。 示例包括地址空间布局随机化(ASLR)[Ref-58][Ref-60]和位置独立可执行文件(Pie)[Ref-64]。 有效性: 深度防御 注意: 这不是一个完整的解决方案。但是,它强制攻击者猜测一个未知值,该值会改变每个程序的执行。此外,攻击仍然可能导致拒绝服务,因为典型的响应是退出应用程序。 |
阶段: 操作 策略: 强化环境 使用提供数据执行保护(NX)或其等效功能的CPU和操作系统[Ref-61][Ref-60]。 有效性: 深度防御 注意: 这不是一个完整的解决方案,因为缓冲区溢出可以用来覆盖附近的变量,以危险的方式修改软件的状态。此外,它不能用于需要自我修改代码的情况。最后,攻击仍然可能导致拒绝服务,因为典型的响应是退出应用程序。 |
阶段: 实现 策略: 强化编译与链接 仔细检查编译器警告,消除可能存在安全隐患的问题,例如内存操作中的有符号/无符号不匹配,或者使用未初始化的变量。即使这种弱点很少被利用,单一的失败也可能导致整个系统的妥协。 |
阶段: 架构与设计; 操作 策略: 强化环境 使用完成必要任务所需的最低权限运行代码[Ref-76]。如果可能,请创建仅用于单个任务的具有有限权限的独立帐户。这样,成功的攻击不会立即让攻击者访问软件的其余部分或其环境。例如,数据库应用程序很少需要以数据库管理员的身份运行,特别是在日常操作中。 |
阶段: 架构与设计; 操作 策略: 沙箱或牢房 在“监狱”或类似的沙盒环境中运行代码,该环境强制在进程和操作系统之间建立严格的边界。这可能有效地限制哪些文件可以在特定目录中访问,或者哪些命令可以由软件执行。 操作系统级的例子包括unix chrot-guille、apparmor和selinux。一般来说,托管代码可能提供一些保护。例如,Java安全管理器中的java. Io.FielEn允许允许软件指定对文件操作的限制。 这可能不是一个可行的解决方案,它只限制了对操作系统的影响;应用程序的其余部分可能仍然会受到影响。 小心避免与监狱有关的CWE-243和其他弱点。 有效性: 有限 注意:此缓解措施的有效性取决于所使用的特定沙箱或牢房的预防能力,可能只有助于减少攻击范围,例如限制攻击者进行某些系统调用或限制可访问的文件系统部分。 |
种属
关系 | 类型 | ID | 名称 |
属于 | 742 | CERT C Secure Coding Standard (2008) Chapter 9 - Memory Management (MEM) | |
属于 | 802 | ||
属于 | 865 | ||
属于 | 876 | ||
属于 | 884 | ||
属于 | 974 | ||
属于 | 1158 | ||
属于 | 1162 | SEI CERT C Coding Standard - Guidelines 08. Memory Management (MEM) |
说明
维护
这是一个宽泛的分类,一些例子包括:
- 简单数学错误,
- 错误更新并行计数器,
- 在将一个输入“转换”为另一种格式时,不考虑大小差异(例如,URL规范化或其他可以生成大于原始输入的结果的转换,即“扩展”)。
这种程度的细节很少在公开报告中出现,因此很难找到好的例子
维护
这个弱点可能是一个复合物或链条。它还可能包含分层或透视差异
这个问题可能与许多不同类型的不正确计算(CWE-682)有关,尽管整数溢出(CWE-190)可能是最普遍的。这可能是资源消耗问题(CWE-400)的主要原因,包括不受控制的内存分配(CWE-789)。但是,还必须考虑它与越界缓冲区访问(CWE-119)的关系。