Skip to content
Accueil » The Art of Fuzzing – Smart Contracts

The Art of Fuzzing – Smart Contracts

Author: 2ourc3

Introduction to Smart Contract Auditing with Fuzzing

In this article we are gonna approach auditing smart contracts to detect vulnerabilities through fuzzing. This article assumes that the reader has a decent understanding of Solidity and Smart Contracts or is willing to use google along.

The field is very young, which means there are plenty of fun and exciting vulnerabilities to find. There is the interesting money aspect because smart contracts bug bounties are very lucrative since they have the potential to cause significant financial losses.

Also, the technology in itself is amazing. Smart contracts use a variety of techniques that are interesting to learn about such as Cryptography, distributed computing, state-machine, etc.

There are various methods to search for vulnerabilities in smart contracts – Manual code review, automated code review, fuzzing, symbolic execution, etc.

I have a strong interest in manual code review and dynamic analysis through fuzzing or symbolic execution. I decided to create this article to teach you how to fuzz a Smart Contract for the Ethereum blockchain using Echidna

What is Echidna

Echidna is a weird creature that eats bugs and is highly electro-sensitive

Echidna is a fuzzer designed to test Ethereum smart contracts. What sets Echidna apart from other fuzzers is the fact that it focuses on breaking user-defined proprieties instead of looking for crashes. It uses sophisticated grammar-based fuzzing based on contract ABI to falsify user-defined predicates or Solidity Assertions.

The core Echidna functionality is an executable called Echidna, which takes a contract and a list of invariants (properties that should always remain true) as input. For each invariant, it generates random sequences of calls to the contract and checks if the invariant holds. If it can find some way to falsify the invariant, it prints the call sequence that does so.

Installing Echidna

The installation process is pretty straight-forward

// Installating Slither
pip3 install slither-analyzer --user

// Installing Solc
sudo add-apt-repository ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install solc

Then download one of the latest release of Echidna, extract the archive and profit.

Echidna Testing modes

Property Mode

Echidna properties are Solidity functions. A property must: Have no arguments. Return true if successful. Have its name starting with echidna.

Echidna will: Automatically generate arbitrary transactions to test the property. Report any transactions that lead a property to return false or throw an error. Discard side-effects when calling a property (i.e., if the property changes a state variable, it is discarded after the test).

Echidna requires a constructor without input arguments. If your contract needs specific initialization, you should do it in the constructor. The following function demonstrates how to test a smart contract with writing a property. The smart contract we are going to use the contract Token.sol.

// Use inheritance to separate your contract from your properties:
contract TestToken is Token {
    function echidna_balance_under_1000() public view returns (bool) {
        return balances[msg.sender] <= 1000;
    }
}

You can run Echidna to test that condition using the following command: echidna testtoken.sol --contract TestToken

Echidna found that the property is violated if the backdoor function is called. More details in the docs.

Assertions

Assertions mode allows you to verify that a certain condition is obtained after executing a function. You can insert an assertion using either assert(condition) or by using a special event called AssertionFailed like this event AssertionFailed(uint256); .... if(condition){ emit AssertionFailed(value); }

More details in the docs. You can also read an excellent blog post about assertions here.

dApptest

Using the “dapptest” testing mode, Echidna will report violations using certain functions following how dApptool and foundry work:

  • This mode uses any function name with one or more arguments, which will trigger a failure if they revert, except in one special case. Specifically, if the execution reverts with the special reason “FOUNDRY::ASSUME”, then the test will pass (this emulates how the assume foundry cheat code works)

Foundry is a smart contract development toolchain. You can learn more about it here: https://book.getfoundry.sh/. More information about choosing the right test method of Echidna can be found in the docs.

You should now have a good understanding of the basics usage of Echidna. However i strongly encourage you to check the documentation available since there is a lot of optimization and advanced techniques you can benefit from.

Echidna host a series of tutorials and docs here.

Finding a target to fuzz

A good approach to find a target to fuzz is by searching for an interesting program on Immunefi. Keep in mind that while fuzzing is an automated process, you might still need to invest time in understanding the code and the project you wish to fuzz. Therefore, take the time to find a target that genuinely interests you and makes you feel comfortable spending time understanding the contract’s mechanics.

After searching on Immunefi and applying some filters, I have obtained a list of several potential targets.

I decided to focus on the Optimism project because I had already invested time in understanding it in the past. However, feel free to explore the possibilities based on your interests.

All smart contracts related to the Optimism project can be found on their Github, and the list of all deployed smart contracts in scope is available on the Bug Bounty page.

To successfully fuzz a target, one must comprehend how it functions, establish at least a basic threat model, and decide how to test its security. Before commencing the audit of a target, I always follow the following process

  • Information Gathering: Begin by exploring the project’s website, including the parent project if applicable, to familiarize yourself with the concept and gain a clear understanding of its purpose. Since good documentation is often scarce, take the time to thoroughly read any available documentation to leverage the valuable insights provided by the developers.
  • Code Review: There are various techniques for conducting an efficient code review. You can choose to follow the instruction flow, read it line by line, or use suitable tools that match your preferences. In this context, the primary focus of the code review is to identify fuzzable functions, rather than manually searching for vulnerabilities. I have opted to follow the instruction flow to gain a comprehensive understanding of the overall project.
  • Threat Modeling: Once you start reading the code and have a clear grasp of its functionality, document potential dangerous functions or sensitive data that you come across. Effective threat modeling helps you concentrate on relevant aspects during the code review process.

Information gathering

Optimism is described as follow on the official website – OP Mainnet is a fast, stable, and scalable L2 blockchain built by Ethereum developers, for Ethereum developers. Built as a minimal extension to existing Ethereum software, OP Mainnet’s EVM-equivalent architecture scales your Ethereum apps without surprises. If it works on Ethereum, it works on OP Mainnet at a fraction of the cost.

In other terms, it’s an equivalent network to Ethereum that you can use to spend less fees on gas while executing Ethereum-compatible contracts. It acts as a Layer 2, which means that it relies on a Layer 1 blockchain – Ethereum

Optimism roll-up is a blockchain that piggybacks off of the security of another “parent” blockchain. Specifically, Optimistic Rollups take advantage of the consensus mechanism (like PoW or PoS) of their parent chain instead of providing their own. In OP Mainnet’s case, this parent blockchain is Ethereum. The process is described on the following page https://community.optimism.io/docs/protocol/2-rollup-protocol/

More information about the fault-proof process are discussed here. Here is the list of the contract involved in the Optimism roll-up process:

Other contracts and part of the Optimism project are in-scope, since the goal is to keep this article short (already failed) we ain’t gonna audit the code-base but focus more on the part related to the roll-up process.

Code-Review

We gain a pretty good overview of what the project does, we listed all the contracts. It’s now time to dive into the code. Remember here the goal isn’t to manually review everything but more to find what to fuzz and how to do it.

For the source code available on Github the process is pretty straightforward, simply click on the link and read it. However, deployed smart contracts are actual byte-code encoded. Etherscan offers a contract tab where you can see the decompiled Solidity contract as follow

Now we can start a more laborious step: analyze all the code snippets from all the contracts to find what to fuzz. An easy way to download all the contracts and dependencies at one address using Etherscan is to click on “Open In” then open it in Remix IDE. You can then download the entire project as a zip file.

You can also open the smart contract with “Open In” Blockscan IDE, which embed a Visual Code IDE in your web browser. Here we see how the contract is organized on the left and the actual code on the right


This will now conclude that article, you are now able to analyze a code-base by yourself and write your own property test and use Echidna. You can also try a promising under development fuzzer from Critic Team called Medusa.

It’s now your turn to find a target and run some fuzzing test, see if you can find bugs in the wild and happy hunting!

Reference