Skip to content

Latest commit

 

History

History
15 lines (12 loc) · 1.53 KB

Solution.md

File metadata and controls

15 lines (12 loc) · 1.53 KB

Telephone

This objective of this level is to claim ownership of the contract, which is fairly straightforward. Ownership is set in two places: in the constructor() and changeOwner(). Since we cannot set the owner in the constructor, we want to focus on changeOwner():

function changeOwner(address _owner) public {
    if (tx.origin != msg.sender) {
      owner = _owner;
    }
}

The function checks whether tx.origin, is not equal to msg.sender. To exploit this contract, we need to know the difference betwen tx.origin and msg.sender: tx.origin refers to the original external account that started the transaction while msg.sender refers to the immediate account, which can be an EOA or a contract, that invokes the function. With msg.sender the owner can be a contract but with tx.origin the owner can never be a contract.

If an EOA calls contract A, both the msg.sender and tx.origin would be equal to the address of the EOA. If contract A makes a call to contract B, however, then the msg.sender would be equal to the address of contract A and the tx.origin would be equal to the address of the EOA.

Thus, in order to claim ownership of the contract and satisfy the if statement, we need to make sure that our msg.sender and tx.origin are not equivalent. This can be done by using an intermediart contract which makes a call to Ethernaut's contract. In AttackTelephone.sol, we create a hack contract that calls changeOwner() from Telephone.sol in its constructor, so we don't have to make any separate calls.