Skip to content

Commit

Permalink
New Ethernaut lvls (#10)
Browse files Browse the repository at this point in the history
* make lev-solutions great again

* ethernaut lvls 17, 21, 22, 23, 24

* re-generate files

---------

Co-authored-by: sojaleiss <[email protected]>
Co-authored-by: LEV Bot <[email protected]>
  • Loading branch information
3 people authored Sep 1, 2023
1 parent 296392a commit c1b517c
Show file tree
Hide file tree
Showing 153 changed files with 3,176 additions and 296 deletions.
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ exclude = [".github/", "**/tests/", "**/contracts/", "**/cache/", "**/out/"]

[workspace.dependencies]
eyre = "0.6"
ethers = "2.0.8"
rand = "0.8.5"
serde = "1.0.164"
serde_json = "1.0.99"
async-trait = "0.1.68"
tokio = { version = "1.19", features = ["macros", "rt-multi-thread", "time"] }
ethers = { version = "2", default-features = false, features = ["rustls"] }
1 change: 0 additions & 1 deletion attack/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
name = "attack"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Expand Down
4 changes: 2 additions & 2 deletions attack/src/abi/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ pub mod example {
pub static EXAMPLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> =
::ethers::contract::Lazy::new(__abi);
#[rustfmt::skip]
const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x163\x17\x90U`\xAB\x80a\x000`\09`\0\xF3\xFE`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x14`-W[`\0\x80\xFD[`\0T`L\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 \xD3\xF6\xCD\xDF\xC7u\x0B\x02\x98\x97\xDD\x85\x87\xD0\xE8\x85\n\xD9O\x06>\xBB\xE4\x8D\xF7\x9E\xB5\x9BB\x80\xCE<dsolcC\0\x08\x14\x003";
const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\0\x80T`\x01`\x01`\xA0\x1B\x03\x19\x163\x17\x90U`\xAB\x80a\x000`\09`\0\xF3\xFE`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x14`-W[`\0\x80\xFD[`\0T`L\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 \xB0\"\xA8\xF1t\xD1\xE3nyUxV\x89\x12\x15\xD5'\xBC\x19D\xEA\xDB\x80\xC9E\xA1 \x1AU\x0B\x82UdsolcC\0\x08\x15\x003";
/// The bytecode of the contract.
pub static EXAMPLE_BYTECODE: ::ethers::core::types::Bytes =
::ethers::core::types::Bytes::from_static(__BYTECODE);
#[rustfmt::skip]
const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x14`-W[`\0\x80\xFD[`\0T`L\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 \xD3\xF6\xCD\xDF\xC7u\x0B\x02\x98\x97\xDD\x85\x87\xD0\xE8\x85\n\xD9O\x06>\xBB\xE4\x8D\xF7\x9E\xB5\x9BB\x80\xCE<dsolcC\0\x08\x14\x003";
const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`(W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x14`-W[`\0\x80\xFD[`\0T`L\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`@Q\x80\x91\x03\x90\xF3\xFE\xA2dipfsX\"\x12 \xB0\"\xA8\xF1t\xD1\xE3nyUxV\x89\x12\x15\xD5'\xBC\x19D\xEA\xDB\x80\xC9E\xA1 \x1AU\x0B\x82UdsolcC\0\x08\x15\x003";
/// The deployed bytecode of the contract.
pub static EXAMPLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes =
::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE);
Expand Down
4 changes: 2 additions & 2 deletions attack/src/abi/std_style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ pub mod std_style {
::ethers::core::abi::Abi,
> = ::ethers::contract::Lazy::new(__abi);
#[rustfmt::skip]
const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x89?\x80n|\x13\xAB\xCE\xBE\xF2\x03*\x9Dt\xF2F\x14\x1E@\x0E\xC4\xAB\xDD\xC9]\xFD-\x88\xC9\xA9\xABRdsolcC\0\x08\x14\x003";
const __BYTECODE: &[u8] = b"`V`7`\x0B\x82\x82\x829\x80Q`\0\x1A`s\x14`*WcNH{q`\xE0\x1B`\0R`\0`\x04R`$`\0\xFD[0`\0R`s\x81S\x82\x81\xF3\xFEs\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 ? \x86\xF6\xD3\xDEg\x96 v\xA8|\xD8vK\x02\x86\xAB\x82>\xE9\x93\xA6.\x8C\xA4\xFB\xC69J\xFD\xB9dsolcC\0\x08\x15\x003";
/// The bytecode of the contract.
pub static STDSTYLE_BYTECODE: ::ethers::core::types::Bytes =
::ethers::core::types::Bytes::from_static(__BYTECODE);
#[rustfmt::skip]
const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 \x89?\x80n|\x13\xAB\xCE\xBE\xF2\x03*\x9Dt\xF2F\x14\x1E@\x0E\xC4\xAB\xDD\xC9]\xFD-\x88\xC9\xA9\xABRdsolcC\0\x08\x14\x003";
const __DEPLOYED_BYTECODE: &[u8] = b"s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x000\x14`\x80`@R`\0\x80\xFD\xFE\xA2dipfsX\"\x12 ? \x86\xF6\xD3\xDEg\x96 v\xA8|\xD8vK\x02\x86\xAB\x82>\xE9\x93\xA6.\x8C\xA4\xFB\xC69J\xFD\xB9dsolcC\0\x08\x15\x003";
/// The deployed bytecode of the contract.
pub static STDSTYLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes =
::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE);
Expand Down
12 changes: 6 additions & 6 deletions ctf/contracts/ethernaut/lvl12/Privacy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ pragma solidity ^0.8.0;
* Advanced gameplay could involve using remix, or your own web3 provider.
*/
contract Privacy {
bool public locked = true;
uint256 public ID = block.timestamp;
uint8 private flattening = 10;
uint8 private denomination = 255;
uint16 private awkwardness = uint16(block.timestamp);
bytes32[3] private data;
bool public locked = true; // 1 byte | slot 0
uint256 public ID = block.timestamp; // 32 bytes | slot 1
uint8 private flattening = 10; // 1 byte | slot 2
uint8 private denomination = 255; // 1 byte | slot 2
uint16 private awkwardness = uint16(block.timestamp); // 2 bytes | slot 2
bytes32[3] private data; //32 * 3 = 96 bytes | slots 3, 4, 5, 6

constructor(bytes32[3] memory _data) {
data = _data;
Expand Down
14 changes: 14 additions & 0 deletions ctf/contracts/ethernaut/lvl14/GatekeeperTwo.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
This gatekeeper introduces a few new challenges.
Register as an entrant to pass this level.
Things that might help:
- Remember what you've learned from getting past
the first gatekeeper - the first gate is the same.
- The assembly keyword in the second gate allows a contract to access
functionality that is not native to vanilla Solidity.
See here for more information. The extcodesize call in this gate will get the size of a contract's code at a given address - you can learn more about how and when this is set in section 7 of the yellow paper.
- The ^ character in the third gate is a bitwise operation (XOR),
and is used here to apply another common bitwise operation (see here).
The Coin Flip level is also a good place to start when approaching this challenge.
*/

contract GatekeeperTwo {
address public entrant;
Expand Down
12 changes: 12 additions & 0 deletions ctf/contracts/ethernaut/lvl15/NaughtCoin.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
NaughtCoin is an ERC20 token and you're already holding all of them.
The catch is that you'll only be able to transfer
them after a 10 year lockout period. Can you figure out how to get them out
to another address so that you can transfer them freely?
Complete this level by getting your token balance to 0.
Things that might help
> The ERC20 Spec
> The OpenZeppelin codebase
*/

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

Expand Down
16 changes: 16 additions & 0 deletions ctf/contracts/ethernaut/lvl16/Preservation.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
This contract utilizes a library to store two different times
for two different timezones. The constructor creates two
instances of the library for each time to be stored.
The goal of this level is for you to claim ownership of the instance you are given.
Things that might help
> Look into Solidity's documentation on the delegatecall low level function,
how it works, how it can be used to delegate operations to on-chain.
libraries, and what implications it has on execution scope.
> Understanding what it means for delegatecall to be context-preserving.
> Understanding how storage variables are stored and accessed.
> Understanding how casting works between different data types.
*/

contract Preservation {
// public library contracts
Expand Down
11 changes: 11 additions & 0 deletions ctf/contracts/ethernaut/lvl17/Recovery.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
* @title Ethernaut Level 17: Recovery
*
* A contract creator has built a very simple token factory contract.
* Anyone can create new tokens with ease. After deploying the first
* token contract, the creator sent `0.001` ether to obtain more tokens.
* They have since lost the contract address.
*
* This level will be completed if you can recover (or remove) the `0.001`
* ether from the lost contract address.
*/
contract Recovery {
//generate tokens
function generateToken(string memory _name, uint256 _initialSupply) public {
Expand Down
10 changes: 10 additions & 0 deletions ctf/contracts/ethernaut/lvl17/RecoverySolution.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract RecoverySolution {
function solution(address creator) public pure returns (address) {
address token =
address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), creator, bytes1(0x01))))));
return token;
}
}
6 changes: 6 additions & 0 deletions ctf/contracts/ethernaut/lvl18/Interface.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface MeaningOfLife {
function whatIsTheMeaningOfLife() external returns (uint256);
}
16 changes: 16 additions & 0 deletions ctf/contracts/ethernaut/lvl18/MagicNumber.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/*
To solve this level, you only need to provide the Ethernaut with a Solver,
a contract that responds to whatIsTheMeaningOfLife() with the right number.
Easy right? Well... there's a catch.
The solver's code needs to be really tiny. Really reaaaaaallly tiny.
Like freakin' really really itty-bitty tiny: 10 opcodes at most.
Hint: Perhaps its time to leave the comfort of the Solidity compiler momentarily,
and build this one by hand O_o. That's right: Raw EVM bytecode.
Good luck!
*/

contract MagicNum {
address public solver;

Expand Down
10 changes: 10 additions & 0 deletions ctf/contracts/ethernaut/lvl19/AlienCodex.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.5.0;

/*
You've uncovered an Alien contract. Claim ownership to complete the level.
Things that might help
> Understanding how array storage works
> Understanding ABI specifications
> Using a very underhanded approach
*/

import "../helpers/Ownable-05.sol";

contract AlienCodex is Ownable {
Expand Down
10 changes: 10 additions & 0 deletions ctf/contracts/ethernaut/lvl20/Denial.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
* @title Ethernaut Level 20: Denial
*
* This is a simple wallet that drips funds over time. You can withdraw the
* funds slowly by becoming a withdrawing partner.
*
* If you can deny the owner from withdrawing funds when they call withdraw()
* (whilst the contract still has funds, and the transaction is of 1M gas or less)
* you will win this level.
*/
contract Denial {
address public partner; // withdrawal partner - pay the gas, split the withdraw
address public constant owner = address(0xA9E);
Expand Down
7 changes: 7 additions & 0 deletions ctf/contracts/ethernaut/lvl21/Shop.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
Сan you get the item from the shop for less than the price asked?
Things that might help:
> Shop expects to be used from a Buyer
> Understanding restrictions of view functions
*/

interface Buyer {
function price() external view returns (uint256);
Expand Down
35 changes: 35 additions & 0 deletions ctf/contracts/ethernaut/lvl22/Dex.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,40 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/*
The goal of this level is for you to hack the basic DEX contract below
and steal the funds by price manipulation.
You will start with 10 tokens of token1 and 10 of token2.
The DEX contract starts with 100 of each token.
You will be successful in this level if you manage
to drain all of at least 1 of the 2 tokens from the contract,
and allow the contract to report a "bad" price of the assets.
Quick note
Normally, when you make a swap with an ERC20 token,
you have to approve the contract to spend your tokens for you.
To keep with the syntax of the game, we've just added the approve method
to the contract itself.
So feel free to use contract.approve(contract.address, <uint amount>)
instead of calling the tokens directly, and it will automatically approve
spending the two tokens by the desired amount.
Feel free to ignore the SwappableToken contract otherwise.
Things that might help:
> How is the price of the token calculated?
> How does the swap method work?
> How do you approve a transaction of an ERC20?
> Theres more than one way to interact with a contract!
> Remix might help
> What does "At Address" do?
*/

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
Expand Down Expand Up @@ -53,6 +87,7 @@ contract SwappableToken is ERC20 {
_dex = dexInstance;
}

// In Rust bindings it's called `approve_with_owner_and_spender`
function approve(address owner, address spender, uint256 amount) public {
require(owner != _dex, "InvalidApprover");
super._approve(owner, spender, amount);
Expand Down
15 changes: 15 additions & 0 deletions ctf/contracts/ethernaut/lvl23/DexTwo.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/*
This level will ask you to break DexTwo,
a subtlely modified Dex contract from the previous level, in a different way.
You need to drain all balances of token1 and token2 from the DexTwo
contract to succeed in this level.
You will still start with 10 tokens of token1 and 10 of token2.
The DEX contract still starts with 100 of each token.
Things that might help:
> How has the swap method been modified?
*/

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
Expand Down
27 changes: 27 additions & 0 deletions ctf/contracts/ethernaut/lvl24/PuzzleWallet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

/*
Nowadays, paying for DeFi operations is impossible, fact.
A group of friends discovered how to slightly decrease the cost
of performing multiple transactions by batching them in one transaction,
so they developed a smart contract for doing this.
They needed this contract to be upgradeable in case the code contained a bug,
and they also wanted to prevent people from outside the group from using it.
To do so, they voted and assigned two people with special roles in the system:
The admin, which has the power of updating the logic of the smart contract.
The owner, which controls the whitelist of addresses allowed to use the contract.
The contracts were deployed, and the group was whitelisted.
Everyone cheered for their accomplishments against evil miners.
Little did they know, their lunch money was at risk…
You'll need to hijack this wallet to become the admin of the proxy.
Things that might help:
> Understanding how delegatecall works and how msg.sender and msg.value behaves
when performing one.
> Knowing about proxy patterns and the way they handle storage variables.
*/

import "../helpers/UpgradeableProxy-08.sol";

contract PuzzleProxy is UpgradeableProxy {
Expand Down
11 changes: 11 additions & 0 deletions ctf/contracts/ethernaut/lvl25/Motorbike.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

pragma solidity <0.7.0;

/*
Ethernaut's motorbike has a brand new upgradeable engine design.
Would you be able to selfdestruct its engine and make the motorbike unusable ?
Things that might help:
> EIP-1967
> UUPS upgradeable pattern
> Initializable contract
*/

import "openzeppelin-contracts-06/utils/Address.sol";
import "openzeppelin-contracts-06/proxy/Initializable.sol";

Expand Down
Loading

0 comments on commit c1b517c

Please sign in to comment.