Awesome
Ethernaut CTF - Foundry edition
What is Ethernaut by OpenZeppelin
Ethernaut is a Web3/Solidity based war game inspired in overthewire.org, to be played in the Ethereum Virtual Machine. Each level is a smart contract that needs to be 'hacked'.
The game acts both as a tool for those interested in learning Ethereum, and as a way to catalog historical hacks in levels. Levels can be infinite, and the game does not require to be played in any particular order.
Created by OpenZeppelin Visit https://ethernaut.openzeppelin.com/
Acknowledgements
Thanks to everyone who had helped me during the making of this project!
Warnings - some solutions are missing!
Ethernaut sometimes rely on old version of solidity to showcase bugs/exploits. Some of those challenges were throwing compilation errors because of solidity compiler incompatibility.
These challenges are not part of the repository:
How to play
Install Foundry
curl -L https://foundry.paradigm.xyz | bash
Update Foundry
foundryup
Clone repo and install dependencies
git clone git@github.com:StErMi/foundry-ethernaut.git
cd foundry-ethernaut
git submodule update --init --recursive
Run a solution
# example forge test --match-contract TestCoinFlip
forge test --match-contract NAME_OF_THE_TEST
Create your own solutions
Create a new test CHALLENGE.t.sol
in the test/
directory and inherit from BaseTest.sol
.
BaseTest.sol will automate all these things:
- The constructor will set up some basic parameters like the number of users to create, how many ethers give them (5 ether) as initial balance and the labels for each user (for better debugging with forge)
- Set up the
Ethernaut
contract - Register the level that you have specified in your
CHALLENGE.t.sol
constructor - Run the test automatically calling two callbacks inside your
CHALLENGE.t.sol
contractsetupLevel
is the function you must override and implement all the logic needed to set up the challenge. Usually is always the same (callcreateLevelInstance
and initialize thelevel
variable)exploitLevel
is the function you must override and implement all the logic to solve the challenge
- Run automatically the
checkSuccess
function that will check if the solution you have provided has solved the challenge
Here's an example of a test
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.6.0;
pragma experimental ABIEncoderV2;
import './utils/BaseTest.sol';
import 'src/levels/CHALLENGE.sol';
import 'src/levels/CHALLENGEFactory.sol';
import '@openzeppelin/contracts/math/SafeMath.sol';
contract TestCHALLENGE is BaseTest {
CoinFlip private level;
constructor() public {
// SETUP LEVEL FACTORY
levelFactory = new CHALLENGEFactory();
}
function setUp() public override {
// Call the BaseTest setUp() function that will also create testsing accounts
super.setUp();
}
function testRunLevel() public {
runLevel();
}
function setupLevel() internal override {
/** CODE YOUR SETUP HERE */
levelAddress = payable(this.createLevelInstance(true));
level = CHALLENGE(levelAddress);
}
function exploitLevel() internal override {
/** CODE YOUR EXPLOIT HERE */
vm.startPrank(player);
// SOLVE THE CHALLENGE!
vm.stopPrank();
}
}
What you need to do is to
- Replace
CHALLENGE
with the name of the Ethernaut challenge you are solving - Modify
setupLevel
if needed - Implement the logic to solve the challenge inside
setupLevel
betweenstartPrank
andstopPrank
- Run the test!
Disclaimer
All Solidity code, practices and patterns in this repository are DAMN VULNERABLE and for educational purposes only.
I do not give any warranties and will not be liable for any loss incurred through any use of this codebase.
DO NOT USE IN PRODUCTION.