コントラクト アドレス:
BunnyMinterV2: https://bscscan.com/address/0x819eea71d3f93bb604816f1797d4828c90219b5d#code
efh:
https://bscscan.com/address/0x73feaa1ee314f8c655e354234017be2193c9e24e#code
pancakePair : https://bscscan.com/address/0x16b9a82891338f9ba80e2d6970fdda79d1eb0dae#code
PancakeRouter: https://bscscan.com/address/0x10ED43C718714eb63d5aA57B78B54704E256024E#code tx
/ 0x88fcffc3256faac76cde4bbd0df6ea3603b1438a5a0409b2e2b91e7c2ba3371a 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)
操作後に操作前の残高を差し引いて計算されます。
同時に、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 が再度呼び出されると、現在のペアのすべての lptoken が焼き付けられ、対応するトークンがターゲット アドレスに送信されます。
事前にlptokenをペアで保存しておくと、関数が呼び出されると、_zapAssetsToBunnyBNB
removeLiquidity操作により、事前に預けられたlptokenもトークンに変換されてコントラクトに送り返され、大量のbnbとusdtが処理されます。契約に来ます。
zapInToken はこれらのトークンを bnb に変換し、(金額の半分を bnb に変換します。bnb の半分) を bunny:bnb プールに 1:1 の比率で入金し、プール内の bnb の数を増やします (価格に影響します)。 bunnyBNBAの金額_zapAssetsToBunnyBNB
も異常に多いです。
zapInToken の運用により(uint valueInBNB,) = priceCalculator.valueOfAsset(BUNNY_BNB, bunnyBNBAmount);
、valueInBNB の計算結果も非常に高くなります。
最終的に大量のバニートークンが生成されました。