Unit underflows and overflows — Ethereum solidity vulnerability
Once smart contracts are deployed to the public network, they had better stay immutable. Any update, such as bug fixes, needs to be adopted by all nodes. Also, the older version of smart contracts needs to be rendered as invalid. This is known as a “hard fork”. It requires all related nodes to update their protocols to the latest version. Otherwise, the continual usage of old versions will cause protocol and data differences than nodes that have been updated to the latest version. This can lead to significant confusion and possible errors.
Therefore, smart contracts’ codes should be as clean as possible before they get deployed to the public network, to avoid future hard forks. One of the most common security pitfalls in smart contracts is the uint underflow/overflow, which could only be fixed with a hard fork. The underflow/overflow issue could cause a catastrophic loss for the crypto holder’s account, and make the crypto hacker rich effortlessly. In this article, we will explain how unit overflows and underflows work in detail.
The uint overflow/underflow, also known as uint wrapping around, is an arithmetic operation that produces a result that is larger than the maximum above for an N-bit integer, or produces a result that is smaller than the minimum below for an N-bit integer.
For instance, for a 2-bit unsigned integer, the maximum value it could express is “11”, and the minimum is “00”. With “11 + 1”, for computers the outcome would be:
11+ 1— — — — 00
For any human calculation, the sum of the max 2-bit integer (99) and the minimal one (01) should be 100. But, for the computer, the 3-bit outcome cascades the 2-bit uint, so the left-most “1” is truncated to have only “00” as the final result (shown above).
How about the subtraction? The computer will calculate “00” minus “1” as below:
00- 1 — — — — 11
Again, the negative sign is truncated, hence only “11” is left, making the MINIMUM number to be MAXIMUM with only one subtraction.
Above examples are called the uint overflow and underflow, also named as integer wrapping. They perform pretty much similar to the odometer:
“All digits are set to the maximum 9 and the next increment of the white digit causes a cascade of carry-over additions setting all digits to 0, but there is no higher digit to change to a 1, so the counter resets to zero. ”
In Solidity, crypto accounts have their balances defined as uint256 type, meaning that any crypto hackers could flip their empty wallet to MAX value without any effort, and any rich man could overflow their wallet with a simple transaction.
Try to subtract 0 to 2²⁵⁶-1, and 2²⁵⁶ — 1 to 0 in this Solidity script:
Press “Compile” on the right -> “Deploy” -> Choose a random address “from Address” -> “Deploy”, Call zero & max to check their initial values before calling any other functions, then call zeroMinus1() and maxPlus1() sequentially. Then test zero & max to see what happens.
In June 2017, OpenZepplin created the “SafeMath” library aiming to tackle the underflow and overflow issues. They implemented safe addiction, subtraction, division, and multiplication, by carefully comparing the operators and operands before the operation. For instance, before running
a — b, the function would firstly assert to ensure
b is smaller than
a, then perform the subtraction.
Again, press “Compile” on the right -> “Deploy” the TestSafeMath column -> Choose a random address “from Address” -> “Deploy”, Call zero & max to check their initial values before calling any other functions, then call zeroMinus1Safe() and maxPlus1Safe() sequentially. Then test zero & max to see what happens.
Pretty cool, right? However there are still uint wrapping cases that have not been taken cared by developers, for instance, VenusADLAB published CVE-2018–13087, which is about integer wrapping issue in MyAdvancedToken’s smart contract. In its mintToken() function, anyone could deceive by minting negative amount of tokens in a zero-balanced account, or minting a large number of tokens to overflow a rich account.
To fix this, assert(), SafeMath library, or require() functions should be adopted to pre-check the operators and maybe rollback an illegal transaction.
Some of the auto-audit tools, like Mythril or Oyente, can also help accurately nail down the Integer wrapping problems. We talked about how to install, deploy and install two of the most popular security auditing tool, Mythril and Oyente in our previous blogs. Please don’t forget to check them out before you publish your smart contracts.