Table of Contents
To get a local copy up and running follow these simple example steps.
-
npm
npm install npm@latest -g
-
hardhat
npm install --save-dev hardhat
npm install @nomiclabs/hardhat-ethers @nomiclabs/hardhat-waffle
OpenZeppelin contract:
npm install @openzeppelin/contracts
run:
npx hardhat
- Clone the repo
git clone https://github.com/Aboudoc/Ethernaut-OpenZeppelin.git
- Install NPM packages
npm install
If you need testnet funds, use the Alchemy testnet faucet.
This project shows my responses of ETHERENAUT challenges. Each challenge comes with a contract that presents a vulnerability.
Fist of all get a new instance from Ethereaut
Use the instance address logged to the console to deploy the exploit. Address of the victim is set in the constructor.
Add your RPC url and private key to .env
file
PRIVATE_KEY=
GOERLI_RPC_URL=
Note: Each challenge can be done/verified on Remix
In solidity, for a contract to be able to receive ether, the fallback function must be marked payable.
However, there is no way to stop an attacker from sending ether to a contract by self destroying. Hence, it is important not to count on the invariant address(this).balance == 0 for any contract logic.
Copy instance address from the console and paste it as vaultAddress
in exploitVault.js
script
Run the exploit:
npx hardhat run scripts/exploitVault --network goerli
Another way getting the password using web3:
await web3.eth.getStorageAt(contract.address, 1)
It's important to remember that marking a variable as private only prevents other contracts from accessing it. State variables marked as private and local variables are still publicly accessible.
To ensure that data is private, it needs to be encrypted before being put onto the blockchain. In this scenario, the decryption key should never be sent on-chain, as it will then be visible to anyone who looks for it. zk-SNARKs provide a way to determine whether someone possesses a secret parameter, without ever having to reveal the parameter.
The King's contract represents a very simple game: whoever sends it an amount of ether that is larger than the current prize becomes the new king. On such an event, the overthrown king gets paid the new prize, making a bit of ether in the process! As ponzi as it gets xD
Such a fun game. Your goal is to break it.
When you submit the instance back to the level, the level is going to reclaim kingship. You will beat the level if you can avoid such a self proclamation.
First, let's check the contract balance. Run it to the console:
await getBalance(contract.address)
The goal is to send more ETH than the actual balance from a malicious contract that doesn't got any receive function. This will revert the transaction sent from King contract and break the game.
Not having a fallback or a receive function is the same as:
fallback() external payable {
revert();
}
Most of Ethernaut's levels try to expose (in an oversimplified form of course) something that actually happened — a real hack or a real bug.
In this case, see: King of the Ether and King of the Ether Postmortem.
The goal of this level is for you to steal all the funds from the contract.
Things that might help:
Untrusted contracts can execute code where you least expect it. Fallback methods Throw/revert bubbling Sometimes the best way to attack a contract is with another contract. See the Help page above, section "Beyond the console"
In order to prevent re-entrancy attacks when moving funds out of your contract, use the Checks-Effects-Interactions pattern being aware that call will only return false without interrupting the execution flow. Solutions such as ReentrancyGuard or PullPayment can also be used.
transfer and send are no longer recommended solutions as they can potentially break contracts after the Istanbul hard fork Source 1 Source 2.
Always assume that the receiver of the funds you are sending can be another contract, not just a regular address. Hence, it can execute code in its payable fallback method and re-enter your contract, possibly messing up your state/logic.
Re-entrancy is a common attack. You should always be prepared for it!
The DAO Hack The famous DAO hack used reentrancy to extract a huge amount of ether from the victim contract. See 15 lines of code that could have prevented TheDAO Hack.
You can use the view function modifier on an interface in order to prevent state modifications. The pure
modifier also prevents functions from modifying the state. Make sure you read Solidity's documentation and learn its caveats.
An alternative way to solve this level is to build a view function which returns different results depends on input data but don't modify state, e.g. gasleft()
.
- Firsts challenges
- Force
- [-] King
- Finish all challenges
See the open issues for a full list of proposed features (and known issues).
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Distributed under the MIT License. See LICENSE.txt
for more information.
Reda Aboutika - @twitter_AboutikaR - reda.aboutika@gmail.com
Project Link: https://github.com/Aboudoc/Ethernaut-OpenZeppelin