类型: 变量 |
|
描述
基于堆栈的缓冲区溢出是指被覆盖的缓冲区是在栈上分配的(例如,是一个局部变量,很少是函数的参数)。
相关视图
与“研究层面”视图(CWE-1000)相关
与“开发层面”视图(CWE-699)相关
引入模式
|
|
架构与设计 |
|
实现 |
应用平台
语言
C
(
出现概率不确定)
C++
(
出现概率不确定)
后果
|
|
|
可利用性 |
技术冲击: 缓冲区溢出通常会导致崩溃。其他导致可用性不足的攻击是可能的,包括将程序放入无限循环。 |
|
完整性 |
技术冲击: 缓冲区溢出通常可用于执行任意代码,这通常不在程序的安全策略的范围内。
|
|
完整性 |
技术冲击: 当结果是任意代码执行时,这通常可以用来破坏任何其他安全服务。 |
被利用的可能性:
高
示例
例1
虽然栈缓冲区溢出示例可能相当复杂,但可能存在非常简单但仍可利用的基于栈的缓冲区溢出:
Example Language:
C
#define BUFSIZE 256
int main(int argc, char **argv) {
char buf[BUFSIZE];
strcpy(buf, argv[1]);
}
缓冲区大小是固定的,但不能保证argv[1]中的字符串不会超过此大小并导致溢出。
例2
此示例从用户获取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字节。如果攻击者指定的地址解析为非常大的主机名,那么我们可能会覆盖敏感数据,甚至将控制流放弃给攻击者。
注意,此示例还包含一个未检查的返回值(CWE-252),它可能导致空指针取消引用(CWE-476)。
应对措施
阶段: 编译及链接 策略: 强化编译与链接 使用自动提供保护机制的功能或扩展运行或编译软件,以减轻或消除缓冲区溢出。 例如,某些编译器和扩展提供了内置于编译代码中的自动缓冲区溢出检测机制。示例包括Microsoft Visual Studio/GS标志、Fedora/Red Hat强化源代码gcc标志、StackGuard和Propolice。 有效性: 深度防御
|
阶段: 架构与设计 使用精简库以屏蔽掉风险API。不是完整的解决方案。 |
阶段: 编译及链接 基于编译器的精巧机制,如stackguard、propolice和Microsoft Visual Studio/GS标志。除非这提供了自动边界检查,否则它不是完整的解决方案 |
阶段: 实现 实现并执行输入边界检查。 |
阶段: 实现 不要使用危险的函数例如gets。使用更安全且功能对等的能够检查边界错误的函数。 |
阶段: 操作 使用操作系统级的预防功能,如aslr。这不是一个完整的解决方案。 |
属种
|
|
|
|
属于 |
|
970 |
|
属于 |
|
1160 |
|
属于 |
|
1161 |
|
说明
其它
基于栈的缓冲区溢出可以在返回地址覆盖、堆栈指针覆盖或帧指针覆盖中实例化。它们还可以被视为“函数指针覆盖”、“数组索引器覆盖”或“任意写入”等。