CWE-120: Buffer Copy without Checking Size of Input(不检查输入数据大小就复制缓冲区)

CWE-120: Buffer Copy without Checking Size of Input(不检查输入数据大小就复制缓冲区)

 ID: 120

类型: 基础
结构: 简单

状态: 不完整

+描述

在没有验证输入缓冲区的长度小于输出缓冲区的长度的情况下,程序复制输入的缓冲区内容到输出的缓冲区,可能会导致缓冲区溢出。

+扩展描述

缓冲区溢出存在于程序试图将多于缓冲区负载能力的数据装入缓冲区的情形,或者当程序试图将数据置入缓冲区边界之外。最简单的错误类型以及最常见的原因是经典案例“程序复制缓冲区而不限制复制复制的数据量大小”。尽管使用了多个变量,但是经典溢出的存在表明程序员甚至没有考虑使用某个变量进行最基本的安全保护。

+相关视图

+同 "研究层面" (CWE-1000) 视图相关

+同 "开发层面" (CWE-699)视图相关

+同"七大毒害王国" (CWE-700)视图

+引入模式

阶段

说明

实现

 

+应用平台

语言

C (出现慨率不确定)

C++ (出现慨率不确定)

类: Assembly (出现慨率不确定)

+后果

范围

冲击

可能性

完整性
机密性
可利用性

技术冲击: 执行未获得授权的代码或命令

 缓冲区溢出经常被用于执行任意代码,这部分代码通常在程序的安全策略范围之外。这通常可用于破坏任何其他安全服务。

 

可利用性

技术冲击: DoS: 崩溃, 退出, 或 重启; DoS: 消耗资源 (CPU)

缓冲区溢出通常会导致崩溃. 其他导致可用性不足的攻击是可能的,包括将程序放入无限循环。

 

+被利用的可能性

+示例

例1

下面代码要求用户输入名子并将其存入last_name数组。

Example Language:

char last_name[20];
printf ("Enter your last name: ");
scanf ("%s", last_name);

上述代码的问题在于,它不限制或限制用户输入的名称的大小。如果用户输入24个字符长的“非常长”姓氏,则会发生缓冲区溢出,因为数组总共只能容纳20个字符

例2

以下代码尝试创建缓冲区的本地副本,以对数据执行一些操作。

Example Language:

void manipulate_string(char* string){

char buf[24];
strcpy(buf, string);
...

}

但是,程序员不能确保字符串指向的数据的大小适合本地缓冲区,并且盲目地使用潜在危险的strcpy()函数复制数据。如果攻击者可以影响字符串参数的内容,这可能会导致缓冲区溢出。

例3

下面的摘录调用了c中的gets()函数,这是不安全的。

Example Language:

char buf[24];
printf("Please enter your name and press \n");
gets(buf);
...

}

但是,程序员使用的函数gets()本质上是不安全的,因为它盲目地将stdin中的所有输入复制到缓冲区,而不限制复制的数量。这允许用户提供大于缓冲区大小的字符串,从而导致溢出条件。

例4

在下面的示例中,服务器接受来自客户机的连接并处理客户机请求。接受客户机连接后,程序将使用gethostbyaddr方法获取客户机信息,复制连接到本地变量的客户机的主机名,并将客户机的主机名输出到日志文件。

Example Language:

...

struct hostent *clienthp;
char hostname[MAX_LEN];

// create server socket, bind to server address and listen on socket
...

// accept client connections and process requests
int count = 0;
for (count = 0; count < MAX_CONNECTIONS; count++) {


int clientlen = sizeof(struct sockaddr_in);
int clientsocket = accept(serversocket, (struct sockaddr *)&clientaddr, &clientlen);

if (clientsocket >= 0) {

clienthp = gethostbyaddr((char*) &clientaddr.sin_addr.s_addr, sizeof(clientaddr.sin_addr.s_addr), AF_INET);
strcpy(hostname, clienthp->h_name);
logOutput("Accepted client connection from host ", hostname);

// process client request
...
close(clientsocket);

}

}
close(serversocket);


...

但是,连接的客户机的主机名可能比为本地主机名变量分配的大小长。当使用strcpy方法将客户机主机名复制到本地变量时,这将导致缓冲区溢出。

+潜在改进措施

阶段: 需求

策略: 语言选择

使用不允许出现这种弱点的语言,或提供使这种弱点更容易避免的结构。

 

例如,执行自己的内存管理的许多语言,如Java和Perl,不受缓冲区溢出的影响。其他语言,如ADA和C#,通常提供溢出保护,但程序员可以禁用该保护。

 

请注意,即使语言本身在理论上是安全的,语言与本机代码的接口仍然可能受到溢出的影响。

阶段:体系结构规划和设计

策略:库或者框架

使用一个经过审查的库或框架,它不允许出现这种弱点,或者提供使这种弱点更容易避免的结构。

 

例如Messier和Viega[Ref-57]的安全c字符串库(safestr)和Microsoft的strsafe.h库[Ref-56]。这些库提供了更安全的易于溢出的字符串处理函数版本。

说明: 这不是一个完整的解决方案,因为许多缓冲区溢出与字符串无关。

阶段: 编译和链接

策略: 强化编译和链接

使用自动提供保护机制的功能或扩展运行或编译软件,以减轻或消除缓冲区溢出。

例如,某些编译器和扩展提供了内置于编译代码中的自动缓冲区溢出检测机制。示例包括Microsoft Visual Studio/GS标志、Fedora/Red Hat强化源代码gcc标志、StackGuard和Propolice。

有效性: 深度防御

说明: 这不一定是一个完整的解决方案,因为这些机制只能检测某些类型的溢出。此外,攻击仍然可能导致拒绝服务,因为典型的响应是退出应用程序。

阶段: 实现

在分配和管理应用程序内存时,请考虑遵守以下规则:

  • 再次检查您的缓冲区是否如您指定的那样大。
  • 当使用接受多个字节进行复制的函数(如strncpy())时,请注意,如果目标缓冲区大小等于源缓冲区大小,则它可能不会为空,从而终止字符串。
  • 如果在一个循环中访问缓冲区,请检查缓冲区边界,并确保不会有写入分配空间的危险。
  • 如有必要,在将所有输入字符串传递给copy和concatenation函数之前,将其截断为合理的长度。

阶段: 实现

策略: 输入验证

假设所有输入都是恶意的。使用“接受已知良好”输入验证策略,即使用严格符合规范的可接受输入白名单。拒绝任何不严格符合规范的输入,或将其转换为符合规范的输入。

在执行输入验证时,请考虑所有潜在的相关属性,包括长度、输入类型、可接受值的完整范围、缺少或额外的输入、语法、相关字段之间的一致性以及对业务规则的一致性。作为业务规则逻辑的一个例子,“boat”在语法上可能有效,因为它只包含字母数字字符,但如果只希望输入包含“red”或“blue”等颜色,则它无效。

不要完全依赖于查找恶意或格式错误的输入(例如,不要依赖黑名单)。黑名单可能会遗漏至少一个不需要的输入,特别是当代码的环境发生变化时。这可以给攻击者足够的空间来绕过预期的验证。然而,黑名单对于检测潜在的攻击或者确定哪些输入是如此的畸形以至于应该直接拒绝它们是有用的。

阶段: 架构与设计

对于在客户端执行的任何安全检查,请确保这些检查在服务器端重复,以避免CWE-602。攻击者可以通过在执行检查后修改值或更改客户端以完全删除客户端检查来绕过客户端检查。然后,这些修改后的值将提交给服务器。

阶段: 操作

策略: 环境强化

使用随机排列程序可执行文件和库在内存中的位置的特性或扩展来运行或编译软件。因为这使得地址不可预测,所以可以防止攻击者可靠地跳到可利用的代码上。

示例包括地址空间布局随机化(ASLR)[Ref-58][Ref-60]和位置独立可执行文件(Pie)[Ref-64]

有效性: 深度防御

说明:这不是一个完整的解决方案。但是,它强制攻击者猜测一个未知值,该值会改变每个程序的执行。此外,攻击仍然可能导致拒绝服务,因为典型的响应是退出应用程序

阶段: 操作

策略: 环境强化

使用提供数据执行保护(NX)或其等效设备的CPU和操作系统[Ref-60][Ref-61]

有效性: 深度防御

说明: 这不是一个完整的解决方案,因为缓冲区溢出可以用来覆盖附近的变量,以危险的方式修改软件的状态。此外,它不能用于需要自我修改代码的情况。最后,攻击仍然可能导致拒绝服务,因为典型的响应是退出应用程序。

阶段: 变异和链接; 操作

迄今为止,编译器或操作系统级别的大多数缓解技术只解决缓冲区溢出问题的一个子集,很少提供对该子集的完整保护。实施策略来增加攻击者的工作负载是一个很好的实践,例如让攻击者猜测一个未知值,该值会改变每个程序的执行。

阶段: 实现

用支持长度参数的类似函数(如strcpy和strncpy)替换无边界复制函数。如果没有,则创建它们。

有效性: 中度

说明: 这种方法仍然容易受到计算错误的影响,包括诸如“差1越界”(CWE-193)和错误计算缓冲区长度(CWE-131)等问题。

阶段: 结构与设计

策略: 转换强化

当可接受对象集(如文件名或URL)受到限制或已知时,创建从一组固定输入值(如数字ID)到实际文件名或URL的映射,并拒绝所有其他输入。

阶段: 规划及设计; 操作

策略: 环境强化

使用完成必要任务所需的最低权限运行代码[Ref-76]。如果可能,请创建仅用于单个任务的具有有限权限的独立帐户。这样,成功的攻击不会立即让攻击者访问软件的其余部分或其环境。例如,数据库应用程序很少需要以数据库管理员的身份运行,特别是在日常操作中。

阶段: 架构与设计; 操作

策略: 沙箱或监狱

在“监狱”或类似的“沙箱”中运行代码,该环境强制在进程和操作系统之间建立严格的边界。这可能有效地限制哪些文件可以在特定目录中访问,或者哪些命令可以由软件执行。

 

操作系统级的例子包括unix chrot-guille、apparmor和selinux。一般来说,托管代码可能提供一些保护。例如,Java安全管理器中的java. Io.FielEn允许允许软件指定对文件操作的限制。

 

这可能不是一个可行的解决方案,它只限制了对操作系统的影响;应用程序的其余部分仍然可能受到损害。

小心避免与监狱有关的CWE-243和其他弱点。

有效性: 有限

说明: 此缓解措施的有效性取决于所使用的特定“沙箱”或“监狱”的预防功能,可能只有助于减少攻击的范围,例如将攻击者限制为某些系统调用或限制可访问的文件系统部分。

+属种

关系

类型

ID

名称

属于

722

OWASP Top Ten 2004 Category A1 - Unvalidated Input

属于

726

OWASP Top Ten 2004 Category A5 - Buffer Overflows

属于

741

CERT C Secure Coding Standard (2008) Chapter 8 - Characters and Strings (STR)

属于

802

2010 Top 25 - Risky Resource Management

属于

865

2011 Top 25 - Risky Resource Management

属于

875

CERT C++ Secure Coding Section 07 - Characters and Strings (STR)

属于

884

CWE Cross-section

属于

970

SFP Secondary Cluster: Faulty Buffer Access

属于

1129

CISQ Quality Measures - Reliability

属于

1131

CISQ Quality Measures - Security

属于

1161

SEI CERT C Coding Standard - Guidelines 07. Characters and Strings (STR)

+说明

关联关系

在代码级别,基于堆栈的溢出和基于堆的溢出没有显著差异,因此通常不需要区分它们。从攻击者的角度来看,它们可能非常不同,因为需要不同的技术来利用它们。

术语

现在称为“缓冲区溢出”的许多问题与“经典”溢出实质上不同,包括完全不同的bug类型,这些类型依赖于溢出利用技术,例如整数签名错误、整数溢出和格式字符串错误。这种不精确的术语会使确定报告的变量变得困难。

你可能感兴趣的:(漏洞检查,白盒测试)