Overflow and Underflow Attacks on Smart Contracts guide.
Consider the following diagram:
That’s a normal odometer which calculates the distance of your car has traveled. This odometer goes from 000000 – 999999. This is why the moment you cross over to 1,000,000 km your odometer will revert back to 000000.
This may have some seriously grave repercussions.
Understanding Overflow and Underflow Attacks on Smart Contracts
Think about the turn of the millennium and the Y2K problem. Y2K was a class of computer bugs that was threatening to cause havoc during the turn of the millennium. To keep it as simple as possible, many programs represented four-digit years with only the final two digits. So, 1998 was stored as 98 and 1999 as 99. However, this would be problematic when the year changes to 2000, since the system will save it as 00 and revert back to 1900.
Both the examples that we have given you above are a class of errors called “integer overflow.” In this guide, we are going to explore the detrimental effects of the overflow and underflow attacks on smart contracts.
The Overflow Error
An overflow occurs when a number gets incremented above its maximum value. Suppose we declare an uint8 variable, which is an unsigned variable and can take up to 8 bits. This means that it can have decimal numbers between 0 and 2^8-1 = 255.
Keeping this in mind, consider the following example.
uint a = 255;
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:
Let’s check the overflow error with a simple token transfer contract (Code taken from GitHub):
So, what do we have here?
There are two “transfer” functions which are used in the program above. One is checking for an overflow, while the other isn’t checking for it. The secure transfer function is checking if the balance reaches the maximum value.
Now, you need to keep one thing in mind. This function may not be relevant all the time especially in the scenario given above. As a developer, one must think if the value is ever going to reach such a high level or are they just needlessly spending gas.
The Underflow Error
Now, we reach the other end of the spectrum, the Underflow error. This works in the exact opposite direction. Remember how uint8 can take values only between 0 and 255? Consider the following code.
unint8 a = 0;
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:
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):
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 error is more likely to happen than the overflow error, because it will be somewhat infeasible for someone to get the required number of tokens to cause an overflow.
Imagine a situation where a token holder has only X tokens. Suppose he tries to spend X+1 tokens. If the program doesn’t even check for that, there is a chance that an attacker will end up with more tokens than what they actually have and get a maxed out balance.
Consider the following example (taken from nethemba):
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 Attacks
4chan’s /biz/ grouped together created “Proof of Weak Hands Coin” or POWH. It was a legit Ponzi Scheme, however, people still bought into it and it grew to over a million dollars.
However, turns out that POWH coin’s developers didn’t secure all the operations and weren’t able to put up the proper defenses against overflow and underflow attacks. Because of this very reason, an unknown hacker was able to siphon away 2000 ETH which was worth ~$2.3 million.