DEV Community

Cover image for Ethernaut Hacks Level 17: Recovery
Naveen ⚡
Naveen ⚡

Posted on

Ethernaut Hacks Level 17: Recovery

This is the level 17 of OpenZeppelin Ethernaut web3/solidity based game.

Pre-requisites

Hack

Given contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import '@openzeppelin/contracts/math/SafeMath.sol';

contract Recovery {

  //generate tokens
  function generateToken(string memory _name, uint256 _initialSupply) public {
    new SimpleToken(_name, msg.sender, _initialSupply);

  }
}

contract SimpleToken {

  using SafeMath for uint256;
  // public variables
  string public name;
  mapping (address => uint) public balances;

  // constructor
  constructor(string memory _name, address _creator, uint256 _initialSupply) public {
    name = _name;
    balances[_creator] = _initialSupply;
  }

  // collect ether in return for tokens
  receive() external payable {
    balances[msg.sender] = msg.value.mul(10);
  }

  // allow transfers of tokens
  function transfer(address _to, uint _amount) public { 
    require(balances[msg.sender] >= _amount);
    balances[msg.sender] = balances[msg.sender].sub(_amount);
    balances[_to] = _amount;
  }

  // clean up after ourselves
  function destroy(address payable _to) public {
    selfdestruct(_to);
  }
}
Enter fullscreen mode Exit fullscreen mode

player has to retrieve the funds from the lost address of contract which was created using the Recovery's first transaction.

If the address of the lost SimpleToken address is retrieved it's funds can be retrieved using the destroy method.

The easiest way to solve this would be to copy the address of Recovery in Etherscan (on Rinkeby network) and inspect transactions in Internal Txns tab. Find the latest Contract Creation transaction and click through the same to get the address of created contract.

Now simply call destroy method at that address.
So, if tokenAddr is the retrieved address then:

functionSignature = {
    name: 'destroy',
    type: 'function',
    inputs: [
        {
            type: 'address',
            name: '_to'
        }
    ]
}

params = [player]

data = web3.eth.abi.encodeFunctionCall(functionSignature, params)

await web3.eth.sendTransaction({from: player, to: tokenAddr, data})
Enter fullscreen mode Exit fullscreen mode

That'd do the job.

Another way to get the lost address is by utilizing the fact that creation of addresses of Ethereum is deterministic and can be calculated by:

 keccack256(address, nonce)
Enter fullscreen mode Exit fullscreen mode

where address is the address of contract that created the transaction and nonce is the number of contracts the creator address has created. You can read more here.

That's it!

Learned something awesome? Consider starring the github repo 😄

and following me on twitter here 🙏

Top comments (0)