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
Press enter or click to view image in full size![]()
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:
Press enter or click to view image in full size![]()
msg.sender is observed in the context of the very last node:Tip:
msg.senderchecks where the external function call directly came from.msg.senderis typically who you want to authenticate.
Detailed Walkthrough
- Notice Telephone.sol’s
changeOwnerfunction 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
