Two years ago, when we began taking on blockchain security engagements, there were no tools engineered for the work. No static analyzers, fuzzers, or reverse engineering tools for Ethereum.
So, we invested significant time and expertise to create what we needed, adapt what we already had, and refine the work continuously over dozens of audits. We’ve filled every gap in the process of creating secure blockchain software.
Today, we’re happy to share most of these tools in the spirit of helping to secure Ethereum’s foundation.
Think of what follows as the roadmap. If you are new to blockchain security, just start at the top. You have all you need. And, if you’re diligent, less reason to worry about succumbing to an attack.
To build a secure Ethereum codebase: get familiar with known mistakes to avoid, run a static analysis on every new checkin of code, fuzz new features, and verify your final product with symbolic execution.
1. Not So Smart Contracts
This repository contains examples of common Ethereum smart contract vulnerabilities, including real code. Review this list to ensure you’re well acquainted with possible issues.
The repository contains a subdirectory for each class of vulnerability, such as integer overflow, reentrancy, and unprotected functions. Each subdirectory contains its own readme and real-world examples of vulnerable contracts. Where appropriate, contracts that exploit the vulnerabilities are also provided.
We use these examples as test cases for our Ethereum bug-finding tools, listed below. The issues in this repository can be used to measure the effectiveness of other tools you develop or use. If you are a smart contract developer, carefully examine the vulnerable code in this repository to fully understand each issue before writing your own contracts.
Slither combines a set of static analyses on Solidity that detect common mistakes such as bugs in reentrancy, constructors, method access, and more. Run Slither as you develop, on every new checkin of code. We continuously incorporate new, unique bugs types that we discover in our audits.
Running Slither is simple:
$ slither.py contract.sol
Slither will then output the vulnerabilities it finds in the contract.
Echidna applies next-generation smart fuzzing to EVM bytecode. Write Echidna tests for your code after you complete new features. It provides simple, high coverage unit tests that discover security bugs. Until your app has 80+% coverage with Echidna, don’t consider it complete.
Using Echidna is simple:
- Add some Echidna tests to your existing code (like in this example),
./echidna-test contract.sol, and
- See if your invariants hold.
If you want to write a fancier analysis (say, abstract state machine testing), we have support for that too.
Manticore uses symbolic execution to simulate complex multi-contract and multi-transaction attacks against EVM bytecode. Once your app is functional, write Manticore tests to discover hidden, unexpected, or dangerous states that it can enter. Manticore enumerates the execution states of your contract and verifies critical functionality.
If your contract doesn’t require initialization parameters, then you can use the command line to easily explore all the possible executions of your smart contract as an attacker or the contract owner:
manticore contract.sol --contract ContractName --txaccount [attacker|owner]
Manticore will generate a list of all the reachable states (including assertion failures and reverts) and the inputs that cause them. It will also automatically flag certain types of issues, like integer overflows and use of uninitialized memory.
Using the Manticore API to review more advanced contracts is simple:
- Initialize your contract with the proper values
- Define symbolic transactions to explore potential states
- Review the list of resulting transactions for undesirable states
Once you’ve developed your smart contract, or you want to look at someone else’s code, you’ll want to use our reversing tools. Load the binary contract into Ethersplay or IDA-EVM. For an instruction set reference, use our EVM Opcodes Database. If you’d like to do more complex analysis, use Rattle.
1. EVM Opcode Database
Whether you’re stepping through code in the Remix debugger or reverse engineering a binary contract, you may want to look up details of EVM instructions. This reference contains a complete and concise list of EVM opcodes and their implementation details. We think this is a big time saver when compared to scrolling through the Yellow Paper, reading Go/Rust source, or checking comments in StackOverflow articles.
Ethersplay is a graphical EVM disassembler capable of method recovery, dynamic jump computation, source code matching, and binary diffing. Use Ethersplay to investigate and debug compiled contracts or contracts already deployed to the blockchain.
Ethersplay takes EVM bytecode as input in either ascii hex encoded or raw binary format. Examples of each are
test.bytecode, respectively. Open the
test.evm file in Binary Ninja, and it will automatically analyze it, identify functions, and generate a control flow graph.
Ethersplay includes two Binary Ninja plugins to help. “EVM Source Code” will correlate contract source to the EVM bytecode. “EVM Manticore Highlight” integrates Manticore with Ethersplay, graphically highlighting code coverage information from Manticore output.
IDA-EVM is a graphical EVM disassembler for IDA Pro capable of function recovery, dynamic jump computation, applying library signatures, and binary diffing using BinDiff.
IDA-EVM allows you to analyze and reverse engineer smart contracts without source. To use it, follow the installation instructions in the readme, then open a .evm or .bytecode file in IDA.
Rattle is an EVM static analyzer that analyzes the EVM bytecode directly for vulnerabilities. It does this by disassembling and recovering the EVM control flow graph and lifting the operations to a Single Static Assignment (SSA) form called EVM::SSA. EVM::SSA optimizes out all pushes, pops, dups, and swaps, often reducing the instruction count by 75%. Rattle will eventually support storage, memory, and argument recovery as well as static security checks similar to those implemented in Slither.
To use Rattle, supply it runtime bytecode from solc or extracted directly from the blockchain:
$ ./rattle -i path/to/input.evm
Work with us!
Please, use the tools, file issues in their respective repos, and participate in their feature and bug bounties. Let us know how they could be better on the Empire Hacking Slack in #ethereum.
Now that we’ve introduced each tool, we plan to write follow-up posts that dig into their details.
EDIT August 10th, 2018: We have released a lot more projects since this blog post was written. Here is a short overview:
- Awesome Ethereum Security – Curated list of awesome Ethereum security references
- Blockchain Security Contacts – Directory of security contacts for blockchain projects
- PyEVMAsm – EVM assembler/disassembler with a CLI and Python API
- Etheno – JSON RPC multiplexer, analysis tool wrapper, and test integration tool.
Pingback: Security for the Blockchain: Exclusive Interview with Trail of Bits Founder and CEO Dan Guido – The Merkle
Pingback: Contract upgrade anti-patterns | Trail of Bits Blog
Pingback: Ethereum security guidance for all | Trail of Bits Blog
Pingback: Watch Your Language: Our First Vyper Audit | Trail of Bits Blog