In Might 2021, we witnessed a number of hacks concentrating on BSC DeFi merchandise. Particularly, a loophole associated to reward minting within the yield aggregator, PancakeBunny, was exploited to mint ~7M BUNNY tokens from nothing, resulting in a whopping $45M monetary loss. After the bloody hack, three forked initiatives — AutoShark, Merlin Labs, and PancakeHunny — had been attacked with related strategies. Amber Group’s Blockchain Safety staff, led by Dr. Chiachih Wu, elaborates on the loophole and provides a step-by-step account of the exploit by reproducing the assault towards PancakeBunny.
Hidden Assault Floor: balanceOf()
Many individuals imagine that composability is essential to the success of DeFi. Token contracts (e.g., ERC20s) play a necessary position on the underside layer of DeFi legos. Nonetheless, builders could overlook some uncontrollable and unpredictable circumstances when integrating ERC20s into their DeFi initiatives. For instance, you’ll be able to’t predict when and what number of tokens you’ll obtain once you retrieve the present token stability. This uncertainty creates a hidden assault floor.
In lots of instances, sensible contracts reference the balances of ERC20s of their enterprise logic. For instance, when a person deposits some XYZ tokens into the sensible contract, XYZ.balanceOf() is invoked to test how a lot cash is obtained. For those who’re acquainted with the Uniswap codebase, you most likely know that the UniswapV2Pair contract has many balanceOf() calls.
Within the code snippet, UniswapV2Pair.mint() makes use of the present balances (balance0, balance1) and the book-keeping information (amount0, amount1) to derive the quantities deposited by the person(amount0, amount1). Nonetheless, if a foul actor transfers some belongings (token1 or token2) proper earlier than the mint() name, the sufferer would supply extra liquidity than anticipated, i.e., extra LP tokens are minted. If the rewards are calculated based mostly on the quantity of LP tokens, the dangerous actor can revenue when the rewards exceed the bills.
The UniswapV2Pair.burn() has the same threat. The mint() perform caller would possibly jeopardize himself with no thorough understanding of the dangers concerned. That is what occurred within the case of PancakeBunny.
Within the code snippet above, line 140 retrieves the stability of LP token by way of balanceOf() and shops it into liquidity. In strains 144–145, the portion of complete LP tokens owned by UniswapV2Pair (i.e., liquidity out of _totalSupply) is used to derive (amount0, amount1) with the present balances (balance0, balance1) of the 2 belongings (i.e., token0 and token1). In a while, (amount0, amount1) of the 2 belongings are transferred to the handle in strains 148–149.
Right here, a foul actor might manipulate (balance0, balance1) and the liquidity by sending some token0+token1 or the LP token into the UniswapV2Pair contract proper earlier than the mint() perform is invoked to make the caller get extra token0+token1 out. We’ll stroll you thru the PancakeBunny supply code and present you ways the dangerous actor can revenue from doing this.
Loophole Evaluation: BunnyMinterV2
Within the PancakeBunny supply code, the BunnyMinterV2.mintForV2() perform is in control of minting BUNNY tokens as rewards. Particularly, the quantity to be minted (i.e., mintBunny)is derived from the enter parameters, _withdrawalFees, and _performanceFee. The computation is expounded to 3 capabilities: _zapAssetsToBunnyBNB() (line 213), priceCalculator.valueOfAsset() (line 219) and amountBunnyToMint() (line 221). For the reason that dangerous actor can mint a considerable amount of BUNNY, the issue lies in one of many three capabilities talked about above.
Let’s begin from the _zapAssetsToBunnyBNB() perform. When the passed-in asset is a Cake-LP (line 267), a certain quantity of LP tokens is used to take away liquidity and take (amountToken0, amountToken1) of (token0, token1) from the liquidity pool (line 278). With the assistance of the zapBSC contract, these belongings are swapped for BUNNY-BNB LP tokens (strains 287–288). A corresponding quantity of BUNNY-BNB LP tokens is then returned to the caller (line 298). Right here, we have now an issue. Does the quantity match the quantity of LP tokens you assume to be burned?
Within the implementation of PancakeV2Router.removeLiquidity(), liquidity of LP tokens (quantity in zapAssetsToBunnyBNB()) could be despatched to the PancakePair contract (line 500) and PancakePair.burn() could be invoked. If the present LP token stability of PancakePair is bigger than 0, the precise quantity to be burned could be better than quantity, which not directly will increase the BUNNY quantity to be minted.
One other subject in _zapAssetsToBunnyBNB() is the zapBSC.zapInToken() name. The logic behind that is to trade the 2 belongings collected by the removeLiquidity() into BUNNY-BNB LP tokens. Since zapBSC swaps belongings via PancakeSwap, the dangerous actor might use flash loans to govern the quantity of swapped BUNNY-BNB.
Again to BunnyMinterV2.mintForV2(), the bunnyBNBAmount returned by zapAssetsToBunnyBNB() could be handed into priceCalculator.valueOfAsset() to cite the worth based mostly on BNB (i.e., vauleInBNB), much like an oracle mechanism.
Nonetheless, priceCalculator.valueOfAsset() references the quantity of BNB and BUNNY (reserve0, reserve1) within the BUNNY_BNB PancakePair as the value feed, which permits the dangerous actor to make use of flash loans to govern the quantity of BUNNY tokens minted.
The amountBunnyToMint() perform is a straightforward math calculation. The enter contribution is multiplied by 5 (bunnyPerProfitBNB = 5e18), which itself has no assault floor, however the amplification magnifies the manipulation talked about above.
Put together for Fight
For the reason that assault is triggered by getReward(), we have to be certified for rewards first.
As proven within the Etherscan screenshot above, the PancakeBunny hacker invoked the init() perform of the exploit contract to trade 1 WBNB to WBNB-USDT-LP tokens and deposit() them into the VaultFlipToFlip contract, such that he would get some rewards by invoking getReward().
As proven above, utilizing the Exp.put together() perform we reproduced the vaultFlipToFlip.deposit() name (line 62). We additionally used the ZapBSC contract to simplify acquiring LP tokens (strains 54-57). Nonetheless, one isn’t capable of get rewards till the PancakeBunny keeper triggers the following harvest() name. For that reason, the PancakeBunny hacker didn’t set off the assault till the primary harvest() transaction following the init() transaction.
In our simulation, no keeper can set off the harvest(). Due to this fact, we leverage the characteristic of eth-brownie to impersonate the keeper and manually provoke the harvest() transaction (line 25).
Recursive Flash Loans
To leverage funds, the PancakeBunny exploiter utilized eight totally different fund swimming pools together with seven PancakePair contracts and the ForTube Financial institution. Right here, Amber Group’s Blockchain Safety staff solely used the next seven PancakePair contracts’ flash-swap characteristic to mortgage 2.3M WBNB:
handle[7] pairs = [ address(0x0eD7e52944161450477ee417DE9Cd3a859b14fD0), address(0x58F876857a02D6762E0101bb5C46A8c1ED44Dc16), address(0x74E4716E431f45807DCF19f284c7aA99F18a4fbc), address(0x61EB789d75A95CAa3fF50ed7E47b96c132fEc082), address(0x9adc6Fb78CEFA07E13E9294F150C1E8C1Dd566c0), address(0xF3Bc6FC080ffCC30d93dF48BFA2aA14b869554bb), address(0xDd5bAd8f8b360d76d12FdA230F8BAF42fe0022CF) ];
To simplify the flash-swap calls, we packed two parameters into the fourth enter argument of the PancakePair.swap() calls (line 72 or line 74): degree and asset. The extent variable signifies which degree of swap() name we’re in; the asset variable is 0 or 1, which means we have to borrow token0 or token1.
Utilizing the callback perform pancakeCall(), we recursively name PancakePair.swap() with degree+1 till we attain the seventh degree. On the high degree, we invoke shellcode() to carry out the true motion in line 98. When shellcode() returns, the asset variable returns the borrowed asset in every corresponding degree (strains 102–104).
Pull the Set off
The shellcode() perform invoked by the seventh degree of pancakeCall() is the precise exploit code. First, we maintain the present stability of WBNB in wbnbAmount (line 108), swap 15,000 WBNB into WBNB-USDT-LP tokens (line 112), and ship them to the contract which minted these LP tokens (i.e., the PancakePair contract) in line 113. This step goals to govern the removeLiquidity() name contained in the _zapAssetsToBunnyBNB() perform as analyzed above, enabling us to obtain extra WBNB+USDT than anticipated.
The second step is to govern the USDT worth referenced by _zapAssetsToBunnyBNB() to swap USDT into WBNB. Since _zapAssetsToBunnyBNB() makes use of WBNB-USDT PancakePair to swap USDT to WBNB, we might swap the remainder of the flash loaned WBNB to USDT on PancakeSwap. Doing so would make WBNB extraordinarily low-cost, and _zapAssetsToBunnyBNB() would obtain a disproportionately great amount of WBNB when swapped from USDT. Be aware that the value manipulation right here happens on the Pancake V1 pool, not Pancake V2’s PancakePair as within the earlier step.
The ultimate step is the getReward() name. The easy contract name might mint 6.9M BUNNY tokens (line 125). The BUNNY tokens might then be swapped for WBNB on PancakeSwap to pay again the flash mortgage.
In our simulation, the dangerous actor pays 1 WBNB and walks away with 104k WBNB + 3.8M USDT (equal to ~$45M).
About Amber Group
Amber Group is a number one international crypto finance service supplier working all over the world and across the clock with a presence in Hong Kong, Taipei, Seoul, and Vancouver. Based in 2017, Amber Group providers over 500 institutional purchasers and has cumulatively traded over $500 billion throughout 100+ digital exchanges, with over $1.5 billion in belongings underneath administration. In 2021, Amber Group raised $100 million in Sequence B funding and have become the most recent FinTech unicorn valued over $1 billion. For extra info, please go to: www.ambergroup.io.