Ethernaut Level 4 Telephone [Foundry-Hardhat]

Ethernaut Level 4 Telephone [Foundry-Hardhat]

ยท

2 min read

The Ethernaut-Solutions repository contains the solutions using Foundry and Hardhat.

This level teaches you the difference between tx.origin and msg.sender. tx.origin and msg.sender are both globally available variables.

Objectives

  • Become the owner of the contract

tx.origin:

  • EOA(Externally Owned Accounts) or The wallet address of the user that initiated the transaction

  • Variable tx.origin will always refer to the external account

  • A contract address can never be tx.origin as contracts cannot initiate transactions

msg.sender:

  • The immediate account that invokes the function

  • msg.sender can be a contract or external account

Consider the following scenarios,

  • In scenario 1, tx.origin and msg.sender are same

  • In scenario 2, tx.origin is constant while msg.sender changes to the address of the intermediate contract.


Analysis

Notice the changeOwner() function of the Telephone contract is public and can be called by anyone.

  function changeOwner(address _owner) public {
    if (tx.origin != msg.sender) {
      owner = _owner;
    }
  }

It checks if tx.origin != msg.sender. So, to exploit the function, we need to make sure tx.origin is not equal to the msg.sender. We can achieve this by creating an intermediary contract that will call this function. We can exploit this condition using scenario 2, as shown in the diagram.


Exploit

Let's create a contract that will hack the level.

Go to the Remix IDE and create the following contract.

Pass the instance address to the constructor while deploying the contract. You can get the instance address by typing instance in the dev console. changeOwner function of the above contract calls the changeOwner of the Telephone contract.

During this transaction, tx.origin is your wallet address, while msg.sender is the address of the TelephoneHack contract. This will pass tx.origin != msg.sender check and set your address as owner.

In the dev console on the Ehternaut site, you check the owner by typing,

await contract.owner()

Submit the instance.

Level passed!!!๐Ÿ˜„


Key Takeaways

  • Never use tx.origin for authorization check

  • Use msg.sender for the authorization of the immediate sender

  • Use (tx.origin == msg.sender)if you want only an EOA can call your contract.

The Ethernaut-Solutions repository contains the solutions using Foundry and Hardhat.

Solution using Foundry:-

Solution using Hardhat:-

More Levels

Did you find this article valuable?

Support Chirag Patil by becoming a sponsor. Any amount is appreciated!

ย