Overflow and Underflow Attacks on Smart Contracts (Blockgeeks Guide)

Consider the following diagram:

That is a standard odometer which computes the space of the car has traveled. This odometer goes in 000000 — even 999999. That is the reason the minute you cross to 1,000,000 kilometers that your odometer will revert back into 000000.

This might involve some severely grave consequences.

Understanding Overflow and Underflow Attacks on Smart Contracts

Understanding Overflow and Underflow Attacks on Smart Contracts

Consider the turn of this century and the Y2K Issue. Y2K was a category of computer bugs which has been threatening to wreak havoc throughout the turn of this millennium. To help keep it as straightforward as you can, many applications represented four-digit decades with just the last 2 digits. Thus, 1998 has been saved since 98 and 1999 since 99. Nevertheless, this could be problematic once the year changes to 2000, because the machine will store it as 00 and revert back to 1900.

Both the cases that we’ve given you are a category of mistakes called”integer overflow.” Inside this informative article, we’re likely to learn more about the detrimental impacts of the overflow and underflow strikes on clever contracts.

The Overflow Error

An overflow happens when a couple gets incremented over its highest possible worth. Suppose we announce that an uint8 factor, which can be an unsigned variable and may take up to 2 pieces. This usually means it may possess decimal numbers between 0 and 2^8-1 = 255.

Bearing this in mind, consider another instance.

uint a = 255;

a++;

This will lead to an overflow because a’s maximum value is 255.

Solidity can handle up to 256-bit numbers. Incrementing by 1 would to an overflow situation:

This will lead to an overflow, because a’s maximum value is 255.

Solidity can handle up to 256 bit numbers. Incrementing by 1 would to an overflow situation:

0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 0x000000000000000000000000000000000001
—————————————-
= 0x000000000000000000000000000000000000

Let’s check the overflow error with a simple token transfer contract (Code taken from GitHub):

mapping (address => uint256) public balanceOf;

// INSECURE
function transfer(address _to, uint256 _value) {
    /* Check if sender has balance */
    require(balanceOf[msg.sender] >= _value);
    /* Add and subtract new balances */
    balanceOf[msg.sender] -= _value;
    balanceOf[_to] += _value;
}

// SECURE

function transfer(address _to, uint256 _value) {
    /* Check if sender has balance and for overflows */
    require(balanceOf[msg.sender] >= _value && balanceOf[_to] + _value >= balanceOf[_to]);

    /* Add and subtract new balances */
    balanceOf[msg.sender] -= _value;
    balanceOf[_to] += _value;
}



So, what exactly do we need here?

There are just two”move” functions that are employed in the program over. One is assessing to get an overflow, whereas another is not checking for this. The secure transport function is assessing whether the equilibrium reaches the highest value.

At this time you have to keep 1 thing in your mind. This function might not be applicable constantly particularly in the situation given above. As a programmer, an individual has to consider whether the value is going to achieve such a higher degree or are they simply needlessly spending petrol.

The Underflow Error

We hit the opposite end of the spectrum, so the Underflow mistake. This functions in the specific opposite way. Recall how uint8 could take values only between 0 and 255? Think about the following code.

unint8 a = 0;

a–;

We just caused an underflow which will cause a to have the maximum possible value which is 255.

Applying the same logic in solidity smart contracts:

0x000000000000000000000000000000000000
– 0x000000000000000000000000000000000001
—————————————-
= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

As you can see, it can lead to serious data misrepresentation.

Let’s check out a piece of code and see how simple underflow can cause havoc in a smart contract(code taken from GitHub):

mapping (address => uint256) public balanceOf;

// INSECURE
function transfer(address _to, uint256 _value) {
    /* Check if sender has balance */
    require(balanceOf[msg.sender] >= _value);
    /* Add and subtract new balances */
    balanceOf[msg.sender] -= _value;
    balanceOf[_to] += _value;
}

// SECURE
function transfer(address _to, uint256 _value) {
    /* Check if sender has balance and for overflows */
    require(balanceOf[msg.sender] >= _value && balanceOf[_to] + _value >= balanceOf[_to]);

    /* Add and subtract new balances */
    balanceOf[msg.sender] -= _value;
    balanceOf[_to] += _value;
}

In the code example given above, a hacker can take advantage of manipulateMe because the dynamic arrays are stored in a sequential manner. All that a hacker needs to do is:

Call popBonusCode to underflow
Compute the storage location of manipulateMe
Modify and update manipulateMe’s value using modifyBonusCode

Obviously it is simple to point out all the errors in isolated functions, however, imagine a long and complicated smart contract with thousands of lines of code. It can be really easy to lose track of such an error while code-checking.

Dangers of Overflow and Underflow Attacks

The underflow mistake is more likely to occur compared to overflow error, since it’s going to be marginally infeasible for somebody to find the necessary amount of tokens to lead to an overflow.

Imagine a scenario in which a token holder includes just X tokens. Guess he attempts to devote X+1 tokens. In case the app does not check for this, there’s a possibility that an attacker is going to wind up with more tokens than that which they have and find a maxed out equilibrium.

Consider the following example (taken from nethemba):

pragma solidity ^0.4.22;

contract Token {

 mapping(address => uint) balances;

 function transfer(address _to, uint _value) public {
   require(balances[msg.sender]  _value >= 0);
   balances[msg.sender] -= _value;
   balances[_to] += _value;
 }
}

In the code given above, the require condition in “transfer” function might look correct at first glance, but only until you realize that operations between two units produce unit value.

What this ultimately means is that the value of balances[msg.sender] – _value >= 0 will always be true regardless of the condition.

Because of this condition, a hacker can actually own more funds than what they actually own and max out their balance. E.g. if the hacker owns 100 tokens and tries to own 101 tokens, they will end up with 100-101 tokens, which gives him 2^256-1 tokens as a result of underflow!

This can simply break the whole system.

Real World Problems Cause by Underflow

4chan’s / / biz/ grouped collectively generated”Proof of Weak Hands Coin” or even POWH. It turned out to be a fictitious Ponzi Scheme, but people still bought into it grew to more than a million bucks.

But turns out the POWH coin programmers did not secure all of the surgeries and were not able to set up the appropriate defenses against overflow and underflow strikes. Due to this reason, an unidentified hacker managed to siphon off 2000 ETH that was worth ~$2.3 million.

Because you may see, it’s essential for a programmer to fortify their defenses from overflow and underflows strikes. As a bounty hunter, then you ought to be on the watch for overflow/underflow strikes.

loading...

Leave a Reply

Your email address will not be published. Required fields are marked *