Smart contracts power much of what has happened in crypto over the past several years. DeFi, web3, and NFTs were all powered by smart contracts on blockchains like Ethereum. As the market for smart contract development continues to balloon, serious exploits have been released that can cost victims tens of thousands of dollars. In this article, we’ll give you an introduction to how to find weaknesses in smart contracts, and what you can do with this knowledge.
We’ll assume, throughout the rest of this article, that you have basic knowledge of working with and using smart contracts. So if you’re still new to smart contracts, you may wish to start here instead: How To Create Your First Smart Contract. If you already know a programming language such as Python,
Even if you aren’t an elite Ethereum dev, that’s okay – we won’t focus on technical minutia. Rather, we’ll jump right into hands-on examples that we’ll explain in a fairly intuitive way. So without further ado, let’s jump in!
Hacking our first smart contract
Just like in the traditional computing world, most smart contract vulnerabilities fall into a few categories of bugs. In smart contracts, the most common of these are:
- Reentrancy Attacks: When a smart contract function can be repeatedly called before its first invocation is completed. The most famous example is the DAO attack, where an attacker was able to repeatedly withdraw funds from the contract
- Integer Overflow and Underflow: If the result of an operation exceeds the maximum (or minimum) value that a variable can hold, it can lead to overflow (or underflow), potentially causing unexpected behavior.
- Access Control Vulnerabilities: If a smart contract does not properly restrict access to its functions, unauthorized users might be able to execute functions that should be restricted, leading to unauthorized actions like changing ownership or withdrawing funds.
- Unchecked External Calls: When a smart contract makes an external call to another contract, it should check the return value to ensure that the call was successful. Failing to do this can lead to unexpected behavior, especially if the called contract has been maliciously crafted or has a bug.
Let’s take a look at one of these bugs using a small snippet of smart contract code.
Hacking an Ethereum smart contract
Ethereum is the blockchain that really brought smart contracts to the forefront of the crypto world, so let’s start there. Consider the following snippet of Solidity code:
pragma solidity ^0.8.0;
contract Vulnerable {
mapping(address => uint) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw() public {
uint balance = balances[msg.sender];
require(balance > 0, "Insufficient balance");
(bool success, ) = msg.sender.call{value: balance}("");
require(success, "Failed to send Ether");
balances[msg.sender] = 0;
}
}
The logic seems good enough, right? Look closer, note how the withdraw
function first sends Ether to the caller and then sets their balance to 0. What does this mean? Well, an attacker can create a malicious contract that re-enters the withdraw
function in its fallback function, allowing them to withdraw their balance multiple times before it is set to 0. For a famous example of this, check out this legendary story about crypto security: What Was The DAO?
So that’s our first taste of an Ethereum-based smart contract vuln. Of course, Ethereum is not the only platform for smart contracts. Let’s see what else is out there!
What about Solana?
We won’t get into the debate about Solana’s speed vs Ethereum’s decentralization. If you’re curious about the differences between the two, you should read this: Solana vs. Ethereum: Investor’s Guide 2024. Moving on, let’s look at a Solana smart contract containing a major vulnerability and try to figure it out.
Note that unlike Ethereum, which has its own programming language for smart contracts, Solana uses Rust. So the smart contract is just a Rust program that uses a special library to interact with the Solana blockchain. It looks like this:
use solana_program::{
account_info::{AccountInfo, next_account_info},
entrypoint,
entrypoint::ProgramResult,
msg,
program_error::ProgramError,
pubkey::Pubkey,
};
entrypoint!(process_instruction);
fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
let accounts_iter = &mut accounts.iter();
let account = next_account_info(accounts_iter)?;
let mut data = account.try_borrow_mut_data()?;
let mut value = u8::from_le_bytes([data[0]]);
// Vulnerable increment that can cause overflow
value = value.wrapping_add(1);
data[0] = value.to_le_bytes()[0];
msg!("Value after increment: {}", value);
Ok(())
}
The code is a tad more verbose than the previous Solidity contract. Rust features elaborate mechanisms to prevent memory bugs, leading to lengthier but more secure code. So, how do we attack this one? The comment tells us where, but how?
In this code, the value
variable increment using wrapping_add
, which allows for overflow without causing a panic. If value
is at the maximum value (255 for a u8
), adding 1 will overflow to 0. To fix this, you would prevent overflow or use a data type that can handle larger values. This exact situation occurred in 2018, when BeautyChain underwent exactly this kind of exploit. You can read about that dramatic case from this essay: A disastrous vulnerability found in smart contracts of BeautyChain (BEC).
As you can see, finding issues in smart contracts has a lot in common with normal security auditing. But what do you do if you want to go deeper into the field and start doing this yourself?
What can you do with smart contract auditing skills?
If the info above intrigues you, the next logical step is to simply start learning all you can about smart contract security. You can do that using the resources below, all of which are among the best learning materials in the industry:
- Smart Contract Audits, Security, and DeFi FULL Course | Learn smart contract auditing
- A Guide to Smart Contract Security
- Official Ethereum docs on smart contract security
Right, so what if you do have the tech knowledge and what to figure out how to turn your DeFi hacking chops into money? Actually, doing so is quite easy. The quickest route is simply bug bounties. However, the platform you’ll use will differ from what you’d use when hunting for web 2.0 bugs. Say goodbye to HackerOne – as a smart contract bug bounty hunter, you’ll want to look at Immenufi.
As the premier bug bounty platform for DeFi, web3, and crypto, they host hundreds of bug bounty programs at a variety of price points and difficulty levels.
You can also find a normal 9-5 remote job on one of the many sites that aggregate jobs in the crypto space. The quality of these sites varies, but we recommend crypto.jobs as a reliable source of crypto employment. Reddit and Twitter also work great for networking with other crypto security fans, which can lead to jobs.
We hope this is the first step into your cryptosec journey, happy hacking!
Leave a Reply