Ethernaut Lvl 4 Telephone Walkthrough: how to abuse tx.origin & msg.sender
This is a in-depth series around Zeppelin team’s smart contract security puzzles. I’ll give you the direct resources and key concepts you’ll need to solve the puzzles 100% on your own.
2 min readAug 18, 2018
This levels requires you to learn the nuances between tx.origin vs msg.sender to claim ownership of the contract.
tx.origin:
- The original user wallet that initiated the transaction
- The origin address of potentially an entire chain of transactions and calls
- Only user wallet addresses can be the
tx.origin
- A contract address can never be the
tx.origin
msg.sender:
- The immediate sender of this specific transaction or call
- Both user wallets and smart contracts can be the
msg.sender
Example scenarios:
Tip:
msg.sender
checks where the external function call directly came from.msg.sender
is typically who you want to authenticate.
Detailed Walkthrough
- Notice Telephone.sol’s
changeOwner
function checks if(tx.origin != msg.sender)
. Seems like we can successfully trigger this function with scenario 3:
2. Create a phone contract, Telephony
to pose as Contract A. Instantiate Contract B, your Telephone.sol, inside Telephony
:
contract Telephony { Telephone public phone = Telephone(YOUR_INSTANCE_ADDR_HERE); //TODO...
}
3. Create a changeOwner
function inside Telephony
that calls the changeOwner
function in Telephone
, i.e. play the game of Telephone.
function changeOwner(address _owner) public {
phone.changeOwner(_owner);
}
4. Notice await contract.owner()
in console now indicate your user wallet is the owner!
Key Security Takeaways
- Never use tx.origin as an authorization check on who’s calling your contracts
- Use msg.sender if you need to authorize the immediate sender