Ethernaut(Lvl 15): Locked Out ; Try to get in and drain it.

Ethernaut(Lvl 15): Locked Out ; Try to get in and drain it.

ERC20's token and bad ICOs . A point of failure that can be exploited

ERC20, short for Ethereum Request for Comment 20, is a protocol within the Ethereum ecosystem that facilitates the creation and management of tokens on the blockchain. It defines a standard interface for smart contracts, outlining ownership and transaction rules for tokens. Initially introduced in 2015, ERC20 gained widespread adoption among developers as it provided a universal API for creating new asset classes. This standardization allowed for the creation of various tokens such as Dogecoin, Kucoin, and Dentacoin, with the assurance that these tokens would be interoperable and accepted by wallets, exchanges, and contracts across the Ethereum network.

ERC20 played a pivotal role in fueling the Initial Coin Offering (ICO) craze of 2017, enabling projects to easily issue and distribute tokens to investors. However, the widespread use of ERC20 tokens also exposed certain security vulnerabilities and issues. One notable issue was the lack of enforcement of SafeMath, which led to the possibility of integer underflows, resulting in unexpected token balances. Additionally, there was confusion regarding the appropriate usage of token transfer functions, with some developers incorrectly using the transfer() function instead of the intended approve() and transferFrom() combination. This misuse resulted in tokens being locked forever in contracts that were not designed to receive them.

Furthermore, some ERC20 token contracts failed to properly implement the ERC interface, leading to various compatibility and functionality issues. For example, the Golem Network Token (GNT) contract lacked the crucial approve() function, limiting the options for token transfers and causing usability challenges. These issues highlighted the importance of thorough testing and adherence to standards when developing ERC20 tokens to ensure their functionality and security within the Ethereum ecosystem.

The Challenge

The challenge presents a NaughtCoin, which is an ERC20 token and you're already holding all of them. The catch is that you'll only be able to transfer them after a 10 year lockout period. Can you figure out how to get them out to another address so that you can transfer them freely? This level can be completed by getting the token balance to 0.

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

import 'openzeppelin-contracts-08/token/ERC20/ERC20.sol';

 contract NaughtCoin is ERC20 {

  // string public constant name = 'NaughtCoin';
  // string public constant symbol = '0x0';
  // uint public constant decimals = 18;
  uint public timeLock = block.timestamp + 10 * 365 days;
  uint256 public INITIAL_SUPPLY;
  address public player;

  constructor(address _player) 
  ERC20('NaughtCoin', '0x0') {
    player = _player;
    INITIAL_SUPPLY = 1000000 * (10**uint256(decimals()));
    // _totalSupply = INITIAL_SUPPLY;
    // _balances[player] = INITIAL_SUPPLY;
    _mint(player, INITIAL_SUPPLY);
    emit Transfer(address(0), player, INITIAL_SUPPLY);
  }

  function transfer(address _to, uint256 _value) override public lockTokens returns(bool) {
    super.transfer(_to, _value);
  }

  // Prevent the initial owner from transferring tokens until the timelock has passed
  modifier lockTokens() {
    if (msg.sender == player) {
      require(block.timestamp > timeLock);
      _;
    } else {
     _;
    }
  } 
}
  1. Access the Contract Instance in Remix:

    • Open Remix IDE and access your contract instance.
  2. Review Contract Functionality:

    • Take note of the available functions and modifiers in the contract instance.

    • Notice that both transfer() and transferFrom() functions are available for moving tokens.

    • Observe that the lockTokens() modifier is only applied to the transfer() function.

  3. Bypassing lockTokens Modifier:

    • Recognize that you can bypass the lockTokens() modifier by using the approve() and transferFrom() functions in combination.

    • Proceed to check your account balance in Remix.

  4. Execute approve() Function:

    • Invoke the approve() function with your own address as the recipient and the exact account balance as the approval amount.
  5. Execute transferFrom() Function:

    • Invoke the transferFrom() function with the following parameters: i) Your address as the sender. ii) An arbitrary external wallet address as the recipient. iii) The approved account balance as the transfer amount.

Developer TidBits

When interacting with contracts or designing your own token standards, it's crucial to implement all available functions to ensure comprehensive functionality and interoperability. Additionally, consider exploring newer token protocols like ERC223, ERC721 (famously used by Cryptokitties), and ERC827 (considered by some as an ERC20 alternative).

For enhanced compatibility and clarity, consider checking for compliance with Ethereum Improvement Proposal (EIP) 165, which verifies the interface implemented by an external contract. Conversely, if you're issuing tokens, strive to maintain EIP-165 compliance to facilitate seamless integration with other contracts and platforms.

To mitigate the risk of token underflows and overflows, always utilize SafeMath when performing arithmetic operations involving token balances or values. This ensures robust security measures are in place to safeguard against unintended mathematical errors that could compromise the integrity of your token contracts.