ID: 195 类型:变量 |
状态:草稿 |
描述
软件使用有符号数据将其强制转换到无符号数据,如果有符号数据的值不能用无符号数据表示,则会产生意外的值
扩展描述
依赖有符号数和无符号数之间的隐式强制转换是很危险的,因为结果可能具有意外的值,并且违反了程序所做的假设。
通常,函数会返回负值来表示失败。当函数的结果用作大小参数时,使用这些负返回值可能会产生意外的结果。例如,如果将负的大小值传递给标准内存复制或分配函数,它们将隐式转换为一个大的无符号值。这可能导致可利用的缓冲区溢出或下溢情况。
相关视图
与“研究层面”视图(CWE-1000)相关
与“开发层面”视图(CWE-699)相关
引入模式
阶段 |
说明 |
实现 |
应用平台
语言
C (出现的可能性不确定)
C++ (出现的可能性不确定)
后果
范围 |
冲击 |
可能性 |
完整性 |
技术冲击: 未知状态 有符号和无符号值之间的转换可以导致各种错误,但从安全角度来说,最常见的是同整数溢出和缓冲区溢出漏洞相关联。 |
示例
例1
在本例中,变量金额在返回时可以保留负值。因为函数声明为返回无符号int,所以金额将隐式转换为无符号。
(问题代码)
Example Language: C
unsigned int readdata () {
int amount = 0;
...
if (result == ERROR)
amount = -1;
...
return amount;
}
如果满足上述代码中的错误条件,则在使用32位整数的系统上,readdata()的返回值将为4294967295。
例2
在本例中,根据accecssMainframe()的返回值,变量量在返回时可以保持负值。因为函数被声明为返回无符号值,所以金额将隐式转换为无符号数字。
(问题代码)
Example Language: C
unsigned int readdata () {
int amount = 0;
...
amount = accessmainframe();
...
return amount;
}
如果accessMainframe()的返回值为-1,那么在使用32位整数的系统上,readData()的返回值将为4294967295。
例3
以下代码用于从套接字读取传入数据包并提取一个或多个头。
(问题代码)
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()使用非常小的正数,然后分配比预期小得多的缓冲区,这可能导致缓冲区溢出。
例4
此示例处理由一系列可变长度结构组成的用户输入。输入的前2个字节指示要处理的结构的大小。
(问题代码)
Example Language: C
char* processNext(char* strm) {
char buf[512];
short len = *(short*) strm;
strm += sizeof(len);
if (len <= 512) {
memcpy(buf, strm, len);
process(buf);
return strm + len;
}
else {
return -1;
}
}
程序员在结构大小上设置了一个上限:如果大于512,则不会处理输入。问题是len是有符号短,因此对最大结构长度的检查是用有符号值完成的,但是len被转换为无符号整数以调用memcpy(),负位将被扩展,从而为无符号整数生成一个巨大的值。如果len为负,那么结构似乎有一个适当的大小(将采用if分支),但是memcpy()复制的内存量将非常大,攻击者将能够用strm中的数据溢出堆栈。
例5
在下面的示例中,可以请求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)可能可用的内存多得多的内存。