Eleven Finance 攻击策略

该次闪电攻击属于很明显的合约逻辑漏洞问题。攻击者使用相同方法发起了多笔攻击交易,我们只需参考其中一笔交易即可,交易链接如下:https://bscscan.com/tx/0x6450d8f4db09972853e948bee44f2cb54b9df786dace774106cd28820e906789

攻击步骤

  1. 从PancakeSwap借入基础资产( 闪电贷)

  2. 将资产转换为Nerve LP 资产

  3. 通过中间金库将Nerve LP 资产存入MasterMind合约

  4. 在中间金库上调用emergencyBurn函数,将等于之前存入的金额(等于攻击前的金库余额)转移给攻击者

  5. 继续常规提款,将先前存入的资产余额转回给攻击者

  6. 还掉闪电贷的费用

出问题的合约来自MasterMind,合约地址为 0x2EBe8CDbCB5fB8564bC45999DAb8DA264E31f24E

下面截取了问题代码

function withdraw(uint256 _pid, uint256 _amount) public {
    PoolInfo storage pool = poolInfo[_pid];
    UserInfo storage user = userInfo[_pid][msg.sender];
    require(user.amount >= _amount, "withdraw: not good");
    updatePool(_pid);
    uint256 pending =
        user.amount.mul(pool.accNervePerShare).div(1e12).sub(
            user.rewardDebt
        );
    safeNerveTransfer(msg.sender, pending);
    user.amount = user.amount.sub(_amount);
    user.rewardDebt = user.amount.mul(pool.accNervePerShare).div(1e12);
    pool.lpToken.safeTransfer(address(msg.sender), _amount);
    emit Withdraw(msg.sender, _pid, _amount);
}

// Withdraw without caring about rewards. EMERGENCY ONLY.
function emergencyWithdraw(uint256 _pid) public {
    PoolInfo storage pool = poolInfo[_pid];
    UserInfo storage user = userInfo[_pid][msg.sender];
    pool.lpToken.safeTransfer(address(msg.sender), user.amount);
    emit EmergencyWithdraw(msg.sender, _pid, user.amount);
    user.amount = 0;
    user.rewardDebt = 0;
}

函数emergencyBurn内部允许攻击者提取存款余额,却没有像上面withdraw函数有做燃烧动作,减去用户在合约的代币余额。导致结果是,攻击者不仅能够取出他自己的存款,而且还能够取出与之前金库中相同金额的全部余额。

Last updated