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 accountA 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
andmsg.sender
are sameIn scenario 2,
tx.origin
is constant whilemsg.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 checkUse
msg.sender
for the authorization of the immediate senderUse
(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