paint-brush
Decoding Overflow And Underflow Vulnerability in Smart Contractsby@web3maya
346 reads
346 reads

Decoding Overflow And Underflow Vulnerability in Smart Contracts

by Web3 MayaDecember 25th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Solving Ethernaut’s - TOKEN Challenge will help you understand overflow and underflow vulnerability of solidity. We'll understand the vulnerability, analyze the code & then apply what we learned to solve the challenge. We'll also go through a real life example where this vulnerability was exploited by a hacker & millions ere compromised
featured image - Decoding Overflow And Underflow Vulnerability in Smart Contracts
Web3 Maya HackerNoon profile picture

We’ll understand overflow and underflow vulnerability of solidity by Solving Ethernaut’sTOKEN Challenge. If you haven’t solved the Ethernaut Challenges already, but are planning to try it out, this might be a spoiler. Come back after solving the Token Challenge

When it comes to smart contracts, even a small bug in the code can cost you millions of dollars. So, it becomes essential to audit smart contracts & make sure there is no vulnerability in the code that can be exploited by a hacker.

Integers in Solidity

Ethereum Virtual Machine specifies a fixed range for all integers. An integer variable can only store a certain range of numbers.

uint8 => range is 0 to 255, i.e. 8 bits or 1 byte or 1 byte (lowest size range)

uint256 => range is 0 to 2²⁵⁶- 1, i.e. 256 bits or 32 bytes (highest size range

OVERFLOW

A number is too big & the part that exceeds the maximum range is counted from zero again. so we end up with a number that is smaller than what we started with.

Solidity

How does solidity handle a number that is bigger than this range?

It circles back to where it started, i.e. zero, and starts again from there. exceeding the maximum number by 1 would get us to 0, exceeding the max number by 2 would get us to 1, exceeding the max number by 3 would get us back to 2 & so on.

When a number overflows in solidity, it doesn’t give any warnings or errors. It simply doesn’t care.


UNDERFLOW

A number is smaller than the minimum range, so it starts counting back from the maximum number, and we end up with a number greater than what we started with. (It's the opposite of overflow)

Solidity

How does solidity handle a number that is smaller than this range?

It wraps around & jumps to the highest number of the range, i.e. 2²⁵⁶ — 1. One number less than the minimum number would get us to 2²⁵⁶-1 (max number). Two less than the min number would get us to 2²⁵⁶-2, & so on.

And like for overflows, when a number underflows in solidity, it again doesn’t give any warnings or errors.

PREVENTION

Use vetted SafeMath libraries for arithmetic operations consistently throughout the smart contract system. It throws an error whenever there is an overflow or an underflow.


Analyzing Ethernaut’s : TOKEN Challenge

THE CHALLENGE :

The goal of this level is to hack the basic contract token below.

You are given 20 tokens to start with & you will beat the level if you somehow manage to get your hands on any additional tokens. Preferably a very large amount of tokens

First of all, it’s not a good practice to have floating point (^) caret in our pragma compiler. Make sure it is locked (like 0.6.0 ). Then we have two state variables — totalSupply & balances. Balances map addresses to units, showing the funds each address holds. (Line 6)

*Note: unit doesn’t have a size mentioned. In solidity, this is uint256 by default.

And we have a constructor that takes a value (_initialSupply) & stores it in a state variable (totalSupply), which will be the funds mapped to the address of the contract deployer. (balances[msg.sender]).The transfer function takes an address(_to) we gonna transfer the fund & a uint(_value) for the funds we transfer. The function returns a bool (true) when certain requirements are met.

The required function makes sure the funds (_value) we transfer is less than or equal to what we actually have.

If our address has the funds, that amount is subtracted from our address & added to the address we sent the funds to (_to).

At last, we have a balanceOf function which takes an address & shows us the funds it holds.

Checkout out the challenge in Ethernaut.


Solving Ethernaut Level 5: TOKEN

Can you find the flaw in the above smart contract?

Let’s go to the transfer function again & look carefully at the require().

We are given a total balance of 20 tokens in our address.

If we transfer 15 tokens (spent less than our total balance of 20), we’ll be left with 5 tokens in our address.

If we transfer 20 tokens (spent equal to our total balance of 20), we’ll be left with 5 tokens in our address.

But what if we transfer more than our total balance?

What If we transfer 25 tokens (more than our total balance of 20), how will the smart contract behave & how many tokens will we have in our address (if any at all)?

20 – 25 = -5.

The token balance comes out to be -5. But as we know, from line 6, the balance an address holds should be a uint256 (i.e. unsigned integer, it cannot have a negative sign).

So after reaching zero, instead of going to -1, it would wrap around & continue counting backwards from there going to 2²⁵⁶ –1, 2²⁵⁶ –2, 2²⁵⁶ –3, 2²⁵⁶ –4 & finally reach 2²⁵⁶ –5. This means now the balance left in our address after spending 25 tokens would be. (Remember our Underflow vulnerability from before? )

Now if you remember our Ethernaut Challenge, we were told to take out and get as many funds as we can. As the maximum number in the uint256 range is 2²⁵⁶ –1, to get that as the balance left in our account, we must spend one more than our total balance of 20, i.e. 21.

Real Life Example

In 2018, a blockchain security startup known as PeckShield discovered an unusual transaction. The team has set up a system to analyze ERC20 token transfers & send out alerts whenever it discovers anomalous behavior.

The team was greeted by one of these alerts on the 22nd of April (it involved Beauty Chain). PeckShield began looking into the code for the underlying smart contract, which indicated that the transfer involved exploiting a vulnerability that had previously been unknown in the contract.

The company named the vulnerability batchOverflow, which involves an integer overflow at its heart. The vulnerable part of the code was the batch transfer.

To know more about the details of this incident, you can refer to PeckShield’s blog.