Ethernaut 题库闯关 #9 — King

Ethernaut题库闯关连载第9篇, 使用transfer 的注意点。

今天这篇是Ethernaut 题库闯关连载的第9篇,难度等级:有点难。

Ethernaut 题库闯关我已经整理为一个专栏了, 欢迎大家订阅专栏。

挑战 #9:King(国王)

King合约代表了一个非常简单的游戏:谁发送的以太币数量大于当前的奖金,谁就成为新的国王。在这种情况下,被推翻的国王会得到新的奖金,在这个过程中赚取一点以太币! 就像庞氏骗局那样一个有趣的游戏。

你的目标是要破坏这个合约。使自己称为国王之后,其他人再也无法称为国王,你就完成了这个挑战。

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

在查看解题思路之前,可以自己先想一想,停一下,这样才有更大的提高。

本次挑战的关键是了解 transfer 函数的局限。

研究合约

状态变量:

  • address payable king是当前国王的地址。当新的国王即位时,老国王将收到发送到receive函数的msg.value
  • uint public prize;如果你想成为新的国王,你需要向合约发送的最低值ETH,新的国王即位会更新。
  • address payable public owner合约的所有者。

函数:

constructor() public payable {
  owner = msg.sender;  
  king = msg.sender;
  prize = msg.value;
}

构造函数只是设置了合约的变量: owner和当前的 kingmsg.sender(合约的部署者)以及prizeprize 是想成为新国王的最低发送金额。

function _king() public view returns (address payable)

solidity这个函数只是返回当前的国王

receive() external payable

这是我们感兴趣的主要函数。我们已经知道,receive函数是一个特殊的函数,允许合约直接从外部合约或EOA接收ethers,回顾一下receive的代码:

receive() external payable {
  require(msg.value >= prize || msg.sender == owner);
  king.transfer(msg.value);
  king = msg.sender;
  prize = msg.value;
}

我们看到的第一件事是 require(msg.value >= prize || msg.sender == owner)。这个检查允许合约的 owner 始终拥有合约的王权,重设所有的值。 从安全的角度来看,这是一个巨大的问...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Ethernaut CTF
Ethernaut CTF
信奉 CODE IS LAW.