天天看点

CWE-839: Numeric Range Comparison Without Minimum Check(无最小检查的数值范围比较)

 ID: 839

类型:基础

结构:简单

状态:未完成

描述

The program checks a value to ensure that it is less than or equal to a maximum, but it does not also verify that the value is greater than or equal to the minimum.

扩展描述

有些程序使用有符号整数或浮点数,即使它们的值只预期为正或0。验证输入检查可能假定值为正值,并且仅检查最大值。如果值为负数,但代码假定值为正数,则可能会产生错误。如果负值用于内存分配、数组访问、缓冲区访问等,则该错误可能会产生安全后果。最终,该错误可能导致缓冲区溢出或其他类型的内存损坏。

在仅为正数的上下文中使用负数可能会对其他类型的资源产生安全影响。例如,购物车可能会检查用户请求的项目不超过10个,但对-3个项目的请求可能会导致应用程序计算负值并将攻击者的帐户记入贷方。

相关视图

 "研究概念"视图 (CWE-1000)

Nature Type ID Name
ChildOf 1023 Incomplete Comparison with Missing Factors
CanPrecede 119 Improper Restriction of Operations within the Bounds of a Memory Buffer
CanPrecede 124 Buffer Underwrite ('Buffer Underflow')
CanPrecede 195 Signed to Unsigned Conversion Error
CanPrecede 682 Incorrect Calculation

 "开发概念"视图 (CWE-699)

Nature Type ID Name
MemberOf 189 Numeric Errors

应用平台

语言

C (经常出现)

C++ (经常出现)

后果

范围 冲击 可能性

完整性

保密性

可利用性

技术冲击: 修改应用数据; 执行未获授权的代码或命令

攻击者可以修改发送到下游组件的消息或数据的结构,可能会注入命令。

可利用性

技术冲击: DoS: 资源小号 (其它)

在某些情况下,负值可能导致资源消耗。

保密性

完整性

技术冲击: 修改内存; 读内存

如果使用负值访问内存、缓冲区或其他可索引结构,则可以在缓冲区边界之外访问内存。

示例

例1

以下代码用于从套接字读取传入数据包并提取一个或多个头。

(问题代码)

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()使用非常小的正数,然后分配比预期小得多的缓冲区,这可能导致缓冲区溢出。

例2

以下代码读取最大大小,并对该大小执行健全性检查。然后它执行strncpy,假设它不会超过数组的边界。在这个特定的示例中,虽然强制使用“short s”,但short int经常用于实际代码中,例如处理结构化数据的代码。

(问题代码)

Example Language: C 

int GetUntrustedInt () {

return(0x0000FFFF);

}

void main (int argc, char **argv) {

char path[256];

char *input;

int i;

short s;

unsigned int sz;

i = GetUntrustedInt();

s = i;

if (s > 256) {

DiePainfully("go away!\n");

}

sz = s;

printf("i=%d, s=%d, sz=%u\n", i, s, sz);

input = GetUserInput("Enter pathname:");

strncpy(path, input, s);

path[255] = '\0';

printf("Path is: %s\n", path);

}

此代码首先展示了CWE-839的一个示例,允许“s”为负数。当负短“s”转换为无符号整数时,它将成为一个非常大的正整数。当strncpy()使用此转换后的整数时,将导致缓冲区溢出(cwe-119)。

例3

在下面的代码中,该方法从特定数组索引位置的数组中检索一个值,该值作为该方法的输入参数给定。

(问题代码)

Example Language: C 

int getValueFromArray(int *array, int len, int index) {

int value;

// check that the array index is less than the maximum

// length of the array

if (index < len) {

// get the value at the specified index of the array

value = array[index];

}

// if array index is invalid then output error message

// and return value indicating error

else {

printf("Value is: %d\n", array[index]);

value = -1;

}

return value;

}

但是,此方法只验证给定的数组索引是否小于数组的最大长度,但不检查最小值(CWE-839)。这将允许接受负值作为输入数组索引,这将导致越界读取(CWE-125),并允许访问敏感内存。应检查输入数组索引,以验证是否在数组所需的最大和最小范围内(CWE-129)。在这个例子中,if语句应该修改为包含一个最小范围检查,如下所示。

(正确代码)

Example Language: C 

...

// check that the array index is within the correct

// range of values for the array

if (index >= 0 && index < len) {

...

例4

下面的代码显示了一个简单的银行帐户类,其中包含存款和取款方法。

(问题代码)

Example Language: Java 

public class BankAccount {

public final int MAXIMUM_WITHDRAWAL_LIMIT = 350;

// variable for bank account balance

private double accountBalance;

// constructor for BankAccount

public BankAccount() {

accountBalance = 0;

}

// method to deposit amount into BankAccount

public void deposit(double depositAmount) {...}

// method to withdraw amount from BankAccount

public void withdraw(double withdrawAmount) {

if (withdrawAmount < MAXIMUM_WITHDRAWAL_LIMIT) {

double newBalance = accountBalance - withdrawAmount;

accountBalance = newBalance;

}

else {

System.err.println("Withdrawal amount exceeds the maximum limit allowed, please try again...");

...

}

}

// other methods for accessing the BankAccount object

...

}

提取方法包括检查以确保提取金额不超过允许的最大限额,但该方法不检查以确保提取金额大于最小值(CWE-129)。对不包括最小检查的值执行范围检查可能会产生重大的安全影响,在这种情况下,不包括最小范围检查可能会允许使用负值,这将导致使用此类的财务应用程序将钱存入用户帐户而不是提现。在这个例子中,if语句应该修改为包含最小范围检查,如下所示。

(正确代码)

Example Language: Java 

public class BankAccount {

public final int MINIMUM_WITHDRAWAL_LIMIT = 0;

public final int MAXIMUM_WITHDRAWAL_LIMIT = 350;

...

// method to withdraw amount from BankAccount

public void withdraw(double withdrawAmount) {

if (withdrawAmount < MAXIMUM_WITHDRAWAL_LIMIT &&

withdrawAmount > MINIMUM_WITHDRAWAL_LIMIT) {

...

请注意,此示例不会防止并发访问BANKACCOUNT BALANCE变量,请参阅CWE-413和CWE-362。             

虽然它超出了本例的范围,但请注意,在财务计算中使用double或float可能会受到某些类型的攻击,攻击者使用舍入错误来窃取资金。

应对措施

阶段: 实现

策略: 通过转换强化

如果要使用的数字总是正数,请将变量类型从有符号更改为无符号或大小。

阶段: 实现

策略: 验证输入

如果要使用的数字根据规范可能具有负值(因此需要有符号的值),但该数字只能是正数以保持代码的正确性,则包括一个检查以确保该值是正数。

种属

关系 类型 ID 名称
属于 884 CWE Cross-section

继续阅读