pancake闪电贷攻击学习

合约地址:
BunnyMinterV2:https://bscscan.com/address/0x819eea71d3f93bb604816f1797d4828c90219b5d#code
VaultFlipToFlip:https://bscscan.com/address/0xd415e6caa8af7cc17b7abd872a42d5f2c90838ea#code
MasterChefh:https://bscscan.com/address/0x73feaa1ee314f8c655e354234017be2193c9e24e#code
pancakePair:https://bscscan.com/address/0x16b9a82891338f9ba80e2d6970fdda79d1eb0dae#code
PancakeRouter:https://bscscan.com/address/0x10ED43C718714eb63d5aA57B78B54704E256024E#code
攻击交易:
一:https://bscscan.com/tx/0x88fcffc3256faac76cde4bbd0df6ea3603b1438a5a0409b2e2b91e7c2ba3371a
二:https://bscscan.com/tx/0x897c2de73dd55d7701e1b69ffb3a17b0f4801ced88b0c75fe1551c5fcce6a979
参考文章:
PancakeBunny攻击事件复盘分析 | 零时科技:http://www.xilian.link/depth/75435.html
慢雾:PancakeBunny 黑客分析:
https://slowmist.medium.com/slowmist-pancakebunny-hack-analysis-4a708e284693


合约BunnyMinterv2中函数mintForV2通过performanceFee与valueInBNB 计算mint生成的数量。

		uint performanceFee = canMint() ? _minter.performanceFee(amount) : 0;        
        if (performanceFee > DUST) {
            _minter.mintForV2(address(_stakingToken), 0, performanceFee, msg.sender, depositTimestamp);
            amount = amount.sub(performanceFee);
        }
function mintForV2(address asset, uint _withdrawalFee, uint _performanceFee, address to, uint) external payable override onlyMinter {
        uint feeSum = _performanceFee.add(_withdrawalFee);  
        _transferAsset(asset, feeSum);
        if (asset == BUNNY) {
            IBEP20(BUNNY).safeTransfer(DEAD, feeSum);
            return;
        }
        uint bunnyBNBAmount = _zapAssetsToBunnyBNB(asset, feeSum, true);
        if (bunnyBNBAmount == 0) return;

        IBEP20(BUNNY_BNB).safeTransfer(BUNNY_POOL, bunnyBNBAmount);
        IStakingRewards(BUNNY_POOL).notifyRewardAmount(bunnyBNBAmount);

        (uint valueInBNB,) = priceCalculator.valueOfAsset(BUNNY_BNB, bunnyBNBAmount);
        uint contribution = valueInBNB.mul(_performanceFee).div(feeSum);
        uint mintBunny = amountBunnyToMint(contribution);
        if (mintBunny == 0) return;
        _mint(mintBunny, to);
    }

但在函数_zapAssetsToBunnyBNB返回的bunnyBNBAmount数量是由IBEP20(BUNNY_BNB).balanceOf(address(this)).sub(_initBunnyBNBAmount)操作后减操作前的balance计算出来的。
同时中间有removeLiquidity操作。
再看removeLiquidity代码:

function removeLiquidity()
......
address pair = PancakeLibrary.pairFor(factory, tokenA, tokenB);
        IPancakePair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
        (uint amount0, uint amount1) = IPancakePair(pair).burn(to);
.............
 
------------
function burn(address to) external lock returns (uint amount0, uint amount1) {
        (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
        address _token0 = token0;                                // gas savings
        address _token1 = token1;                                // gas savings
        uint balance0 = IERC20(_token0).balanceOf(address(this));
        uint balance1 = IERC20(_token1).balanceOf(address(this));
        uint liquidity = balanceOf[address(this)];
        bool feeOn = _mintFee(_reserve0, _reserve1);
        uint _totalSupply = totalSupply; 
        amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
        amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
        _burn(address(this), liquidity);
        _safeTransfer(_token0, to, amount0);
        _safeTransfer(_token1, to, amount1); 

再调用burn时会将当前pair中的lptoken全部燃烧并发送相应的token到目标地址。
如果将lptoken提前存入pair中,那么在调用函数_zapAssetsToBunnyBNB时因为removeLiquidity的操作,会将提前存入的lptoken也一并转换为token并发送回合约,大量bnb与usdt 来到合约后。
zapInToken又将这些token转换为bnb后再(转换一半数量为bunny。一半bnb)1:1存入bunny:bnb池子,增加池子中bnb数量(影响bunny价格),_zapAssetsToBunnyBNB返回时因为提前存入lp导致返回的 bunnyBNBAmount 数量也异常的大。
(uint valueInBNB,) = priceCalculator.valueOfAsset(BUNNY_BNB, bunnyBNBAmount);时因为zapInToken的操作,导致计算的valueInBNB结果也变得非常高。
最终生成了大量bunnytoken。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值