Solidity Hacking: Integer Overflow and Underflow

Share:

Background

An integer is a whole number, so it has no fractional parts. Integers can be either positive or negative. There are many different ranges of integers that may be used in programming languages, but Solidity uses the 256-bit unsigned integer range. This means the numbers start at 0 and go to 115792089237316195423570985008687907853269984665640564039457584007913129639935 (in decimal).

Solidity will throw an error if you try to assign something that is not an integer to a variable declared as one. You can check out what happens by trying to set a bool (true/false) variable equal to an integer.

When you use integers with mathematical operations, you need to know what happens when values become too large or small for their range. Overflow occurs when the maximum value is exceeded and underflow occurs when the minimum value is exceeded.

Solidity

Solidity is a contract-oriented, high-level language for implementing smart contracts. It was influenced by C++, Python and JavaScript and is designed to target the Ethereum Virtual Machine (EVM).

Solidity is statically typed, supports inheritance, libraries and complex user-defined types among other features.

Integer Overflow and Underflow

Integer overflow and underflow are vulnerabilities that can lead to the theft of funds or other information in a smart contract. This article explains what these vulnerabilities are, why they’re important to understand, and how to avoid them.

In Solidity, integers are signed unless marked with an uppercase ‘U’ at the end. An unsigned integer is of type uint; a signed integer is of type int.

The range of values for a signed 256-bit number (int256) is from -(2²⁵⁵) to 2²⁵⁵ — 1. The range for an unsigned 256-bit number (uint256) is from 0 to 2²⁵⁶ — 1.

Value Ranges for Integers

Contract Code Example

function deposit() public payable{

_balance[msg.sender] = _balance[msg.sender].add(msg.value); //Add method of SafeMath library is used to add two numbers and throws an error if the calculation overflows/underflows a type

}

function withdraw(uint256 amount) public {

require(_balance[msg.sender] >= amount, “Insufficient balance”); //checking for sufficient balance before withdrawing funds

_balance[msg.sender] = _balance[msg.sender].sub(amount); //Subtract method of SafeMath library is used to subtract two numbers and throws an error if the calculation overflows/underflows a type

msg.sender.transfer(amount); //send funds back to the caller address

}

function withdrawAll() public {

uint256 amount = _balance[msg.sender]; //store balance in amount variable so that we can use it after resetting the mapping value to 0 as part of withdrawAll process

_balance[msg.sender] = 0; //reset the mapping value after storing current balance in temporary variable (amount)

msg.sender.transfer(amount); // send entire balance back to the caller address by using transfer method on msg object which represents sender address (caller’s address)

}

Attack Vectors

There are a few ways that you can leverage integer underflow/overflow to get the math results you want.

  • Call the function with a large amount. If you give the function an input value of uint256(2)²⁵⁶ — 1, it will return 0. This is an easy way to ‘zero out’ balance!
  • Call the function with a negative amount multiple times. If you call the function three times with (uint256(-1)), it will add 2⁸ — 3, resulting in 2⁸ — 1, and if we were to call this again it would result in 0! You could repeat this to create any number less than 2⁸ using just 8 calls! The same idea works for 256 bit numbers as well if your contract has enough gas.
  • Call the function with a negative amount 101 times or more. Calling transfer(uint(-1)) 101 times will set your balance to MAX_UINT instead of MIN_UINT, since adding 101 * (-1) is equivalent to subtracting 101 from your balance, which overflows at 255 and becomes MAX_UINT.

Be careful when using integers in smart contract code!

The Solidity programming language was developed to help write Ethereum smart contracts. It’s the most popular choice for writing smart contracts today.

Solidity is a language that compiles down to Ethereum Virtual Machine (EVM) bytecode and gets stored on the blockchain. The EVM is a runtime environment that executes smart contract code and manages its state, but it lacks certain features which we take for granted when working with other programming languages like JavaScript. In particular, there’s no built-in support for unsigned integers in Solidity, so if you aren’t careful when using them, your contract can be vulnerable to integer overflow/underflow bugs!

Integer overflow/underflow happens when you try to store something larger than what can fit in an integer variable or less than 0 in an unsigned integer variable. Any time this happens, instead of getting the expected result, an unintended value will be assigned to the variable instead.