The CyberNews.com Investigation team’s analysis of Ethereum smart contracts – essentially code that helps online services send and receive payments – from shows that nearly 3,800 smart contracts have severe weaknesses that can allow cybercriminals to quickly steal 1 million dollars.
One of the most famous Ethereum smart contract vulnerabilities is what’s known as a reentrancy attack, which in 2016 allowed a cybercriminal to steal $50 million.
We scanned 6 months’ worth of blocks from Ethereum’s blockchain and found that 3,779 contracts have 13 different types of vulnerabilities, including 4 high-severity vulnerabilities. The total value of these vulnerable smart contracts is 2,088 ETH, which equals $964,172.
One of these high-severity vulnerabilities is the integer underflow, which allows someone with no funds in their account to send out one token, and receive billions of tokens in return. Another is the unprotected selfdestruct, which would allow any attacker to kill the contract and withdraw all the funds to any address.
These vulnerabilities, while specific and technical in nature, basically allow attackers to fiddle with the code and steal as much money as possible in a very short amount of time.
In order to undertake our analysis, we performed the following steps:
- We scanned 6 months’ worth of blocks on the Ethereum network for smart contracts
- We performed a static analysis of these contracts using three tools: Slither, Securify and Oyente
- Once notified of the vulnerabilities, we deployed the same contract over Testnet – Ethereum’s secondary blockchain that’s used for testing purposes and holds no real value – and we attempted to exploit those contracts to confirm the vulnerabilities
Of the total blocks that were scanned, 3,779 contracts were shown to have the four following high-severity vulnerabilities:
- Integer underflow: when an attacker has zero balance and sends one token, the contract circles around and gives the attacker the maximum value of tokens – about 4.3 billion
- Integer overflow: when the balance reaches its maximum value, and an attacker receives one token, it circles around and starts from zero
- Unprotected Ether withdrawal: due to inadequate access control, any attacker can withdraw Ether funds from the contract
- Unprotected selfdestruct: any attacker can kill the contract and send the balance to any specified address
You can find a full list of the vulnerabilities in the table at the end of the article.
Understanding Ethereum smart contracts
Ethereum is the second-largest cryptocurrency platform in the world, and it is also a cryptocurrency in and of itself. As a platform, 1,900 different cryptocurrencies and tokens are built on top of it.
Smart contracts on Ethereum help people and organizations exchange money, or really anything of value, in a transparent way that doesn’t require any middlemen. Smart contracts are simply code that define the rules and penalties between two parties (the buyer and seller, for example).
These smart contracts also automatically enforce those obligations – again, since there are no middlemen. This means that online services and platforms can use smart contracts to send and receive payments on Ethereum without needing to involve any third parties.
The underflow attack
In order to understand an integer underflow attack, we need to cover a few basics (warning: there’s some math involved).
Ethereum smart contracts are built using 256 bits as its word size. Practically, this means that the allowed numbers on Ethereum contracts range from 0 all the way to 4,294,967,295 (or 2²⁵⁶), which is approximately 4.3 billion, and there are no negative numbers allowed.
Now, in an integer overflow, if you add 1 to the top of the range, it’ll cycle back down to zero (2²⁵⁶ + 1 = 0), kind of like an odometer in a really old car. In an integer underflow, it’s the opposite – if you subtract 1 from zero, you’ll cycle all the way to the top of the range (0–1= 2²⁵⁶).
An integer underflow attack then involves a malicious user with zero balance sending just one token to a friend. Because of the vulnerability, the malicious user’s balance now goes from zero all the way to nearly 4.3 billion. To complete the attack, the malicious user withdraws all that free money to a wallet.
Although the integer underflow and overflow attacks are caused by the same issue, the underflow attack is much more practical since it’s easier for a user to have a zero balance than a 4.3 billion balance of a given token.
The unprotected attacks
Lastly, there’s the unprotected selfdestruct and unprotected Ether withdrawal vulnerabilities.
Both of these have to do with a common weakness known as “improper access control,” which essentially means that the contract didn’t have enough protections in place to stop an attacker accessing these critical functions. These are also the simplest attacks to understand.
In terms of the unprotected Ether withdrawal vulnerability, any attacker can withdraw Ether tokens from the contract without needing to first send an equivalent amount of tokens to the contract.
For the unprotected selfdestruct vulnerability, the weakness allows any attacker to kill the contract and then withdraw any balance from the contract to any specified address.
Previous vulnerabilities: the 2016 reentrancy attack
For all the sophistication of smart contracts and Ethereum, there are some potentially huge vulnerabilities in the way that smart contracts work. The 2016 reentrancy attack, for example, affected the way that DAO tokens were traded. The DAO – Decentralized Autonomous Organization – was a sort of decentralized venture capital fund.
Because of a fault in the smart contract code, an attacker was able to initiate multiple transfers without actually submitting them. The fault lay in the fact that the attacker was able to continuously withdraw funds, in a near-infinite loop, without actually completing the withdrawal on the contract.
In simpler terms: if for example, you have 10 Ether in your contract, and your contract updates the balance only after withdrawing the funds, you can write a malicious contract that would continuously withdraw those funds without updating the balance. The DAO attack scored $50 million from that smart contract vulnerability.
How this could impact you
These types of vulnerability can certainly impact many users, depending on whether they’ve stored Ethereum-based cryptocurrency or tokens on an online platform that holds money.
These include crypto gambling sites, loan services, Ethereum banks, and other online services where users are likely to hold their coins or tokens. If the attacker creates a malicious smart contract and attacks those sites, users can stand to lose their money.
This is similar to what happened in the 2016 DAO reentrancy attack. In effect, the $50 million that users had put into the DAO was essentially stolen.
In any case, whenever money is stolen from any platform, the user will end up paying in one form or another.
How to fix or avoid this vulnerability
Luckily for users – the average person using these online services – it’s pretty easy to check if the platforms they’re on is using a smart contract with any of these vulnerabilities. They can review the smart contracts on Etherscan or a similar explorer to see if these contracts have been audited and verified.
If the smart contract has not been audited or verified, we’d recommend avoiding that particular platform or online service.
For the developers that have created these smart contracts, there are SWC recommendations for each individual vulnerability (linked in the table below). However, in order to fix a vulnerable smart contract, these developers will have to redo them, fixing the code first to remove the vulnerability.
List of vulnerabilities discovered
In the table below, you will find the different types of vulnerabilities contained within the 3,779 smart contracts. This includes their severity, SWC ID and description, as well as how many times the specific vulnerability was observed (under Instances).
|Vulnerability||Severity||Instances||SWC ID||Short Description|
|Integer Underflow||High||189||101||When an account with zero balance sends out one token, the balance cycles up to the maximum value.|
|Integer Overflow||High||1331||101||When an account with maximum value adds one token, the balance cycles down to zero.|
|Unprotected Ether Withdrawal||High||16||105||The return value of a message call is not checked.This allows for anyone to withdraw funds from the contract.|
|Unprotected Selfdestruct||High||50||106||Anyone can kill this contract and withdraw its balance to an arbitrary address.|
|External Call To User-Supplied Address||Medium||827||107||An external message is sent to an address specified by the caller. Note that the callee account might contain arbitrary code and could re-enter any function with this contract.|
|Use of callcode||Medium||516||The callcode method executes code of another contract in the context of the caller account. It was therefore deprecated and may be removed in the future.|
|Use of tx.origin||Medium||1950||111||The smart contract retrieves the transaction origin (tx.origin) using msg.origin. Use of msg.origin is deprecated and the instruction may be removed in the future.|
|Jump to an arbitrary instruction||Medium||421||127||The caller can jump to any point in the code.This can lead to unintended consequences.|
|State change after external call||Medium||241||107||The contract account state is changed after an external call to a user defined address.|
|Exception State||Low||197||110||A reachable exception has been detected.|
|Dependence on predictable environment variable||Low||613||120||A control flow decision is made based on a predictable variable.|
|Multiple Calls in a Single Transaction||Low||86||113||This call is executed after a previous call in the same transaction.|
|Unchecked Call Return Value||Low||84||104||The return value of a message call is not checked.|