How to exploit integer overflow and underflow
Integer overflows and underflows
Integer overflow and underflow vulnerabilities can exist because of how memory and variables are handled in programming languages. Variables are designed to specify how data should be interpreted.
A variable specifies the range of potential values that a piece of data can be interpreted as. However, since this range has a finite size, the possibility exists that a value being placed within a variable lies outside of this set. This type of issue results in integer overflow and underflow vulnerabilities.
Breaking value checks through vulnerability exploitation
Exploiting an integer overflow or underflow vulnerability requires identifying a place in the code where the value stored in the vulnerable variable is essential to the program’s operation. In many cases, this essential operation will be a value check.
Integers are commonly used to store the size of an array or specify the range of acceptable values for an operation. For example, when making a withdrawal from an account, there is likely an account balance variable that is checked to ensure that the value of the withdrawal is less than or equal to the value stored in the account.
In these situations, an integer overflow or underflow vulnerability could allow an attacker to bypass the value check. This could result in a buffer overflow vulnerability or the use of an unacceptable value for an operation.
Creating buffer overflows
Buffer overflow vulnerabilities are most commonly caused when a program tries to write more data to a memory address than was allocated for that chunk of memory. In these cases, it is possible that memory used elsewhere in the application could be overwritten.
The potential for a buffer overflow vulnerability caused by an integer overflow or underflow vulnerability exists due to a common coding pattern for managing user input. An application may:
- Read in user input
- Determine the length of the data read
- Allocate memory to store the data
- Copy the data to the allocated buffer
As long as the length value for the user-provided data is correct, then this process works well. However, an integer overflow or underflow vulnerability could result in a misallocation of memory.
For example, assume that an application uses an unsigned integer for this length value. If an attacker provides an input equal to the maximum value of an unsigned int plus one, then the allocated memory will have length zero. When the application attempts to copy the data over (assuming that the same overflow does not happen there as well), it will overwrite a large amount of other memory and likely cause a segmentation fault.
Using unacceptable values
Another potential result of an integer overflow or underflow vulnerability is performing an “invalid” operation. An example of this would be an invalid withdrawal from a bank account.
When implementing a withdrawal function, it is common to include a value check comparing the value of the withdrawal request and the account balance. Many programming languages will not allow the comparison of two values of different types (like a signed and unsigned int). Before making the comparison, the application may implicitly typecast one of the values to make a “fair” comparison.
This implicit typecast can cause the value check to be broken. For example, the withdrawal request may be for a very large amount which would be interpreted as a negative number in a signed integer. If this value is stored in an unsigned int, the following could happen:
- During the value check, the withdrawal amount is implicitly typecast to a signed int. This would make it a negative number, which is almost certainly less than the balance of the account. As a result, the value check passes.
- During the transfer, the value is interpreted as an unsigned int, making it a very large number. Since the value check already occurred, this transfer goes through and withdraws more value than is stored in the user’s account.
Under these circumstances, the integer overflow or underflow vulnerability allows the attacker to withdraw much more value than should have been possible. A similar vulnerability was exploited on the Bitcoin blockchain in August 2010.
Integer overflow and underflow security
When using user-controlled values for allocating memory or in value checks, it is essential to ensure that the code is operating as intended. Even small oversights in the implementation – such as comparisons between different variable types – can leave an application open to exploitation.