9

This documentation says

Even if a contract’s code does not contain a call to selfdestruct, it can still perform that operation using delegatecall or callcode.

This worries me.

I've created some pseudo code to give a gist of a possible exploit. The code below creates an "exception: invalid opcode", but you'll be able to follow my logic. Assuming this style of attack works, what can be done to guard against it?

pragma solidity ^0.4.2;        
contract Steal{
      function delegatecall_selfdestruct(address _target) external returns (bool _ans) {
          _ans = _target.delegatecall(bytes4(sha3("selfdestruct(address)")), this); 
      }
}

contract Mark { 
  function Deposit() payable {
  }
}

The idea is to send some testnet ETH to the contract Mark then use the Steal contract to call Mark and make it selfdestruct and give the ETH to the Steal Contract.

  • 1
    There's a difference between built-in solidity functions and publicly accessable contract functions. Your attack will not work – Tjaden Hess Apr 10 '17 at 20:15
  • @TjadenHess besides, are there any token listed on an exchange actually using DELEGATECALL or CALLCODE ? – user2284570 Jun 20 '18 at 20:38
12

It doesn't work to just call built-in Solidity functions in other contracts using delegatecall.

What delegatecall really does is call a function in another contract, which executes in the context of the first contract. It's really dangerous to make delegatecalls to contracts you don't trust. The documentation is warning you about this possibility:

pragma solidity ^0.4.2;        
contract Steal{
    address owner;
    function Steal() {
        owner = msg.sender;
    }
    function innocence() {
        selfdestruct(owner);
    }
}

contract Mark { 
    function Deposit() payable {}
    function call(address a) {
        a.delegatecall(bytes4(sha3("innocence()"))); 
    }
}

If Mark calls Steal, then Mark will selfdestruct.

  • 2
    This example helps a lot, but when I test this, Mark calls steal and self destructs, but the ETH that was in Mark gets sent to address 0x0 even though address owner != 0x0. Can you help me understand why, and how a non zero address can be specified? Thanks. – user1938620 Apr 13 '17 at 20:17
  • 2
    I think it must be because owner doesn't exist in Mark, and delegatecall uses Mark's environment, not Steal's. It might be interesting to add an "owner" variable to Mark and see if that gets the ETH. – Dennis Peterson Apr 14 '17 at 20:52
  • @DennisPeterson I can add that Steal can even overwrite Mark bytecode (the bytecode stored at the address of Mark) through a Callcode to address 0 (this will create a contract not as the usual new address but at the address of Mark), because unlike CALL CodeAddr is not null. The bytecode which will be stored over Mark is Steal. – user2284570 Jun 20 '18 at 20:37

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.