amber group

In Might 2021, we witnessed a number of hacks concentrating on BSC DeFi merchandise. Specifically, 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 tasks —  AutoShark, Merlin Labs, and PancakeHunny — have been attacked with comparable methods. Amber Group’s Blockchain Safety staff, led by Dr. Chiachih Wu, elaborates on the loophole and offers a step-by-step account of the exploit by reproducing the assault in opposition to PancakeBunny.

Hidden Assault Floor: balanceOf()

Many individuals consider that composability is essential to the success of DeFi. Token contracts (e.g., ERC20s) play an important position on the underside layer of DeFi legos. Nonetheless, builders might overlook some uncontrollable and unpredictable circumstances when integrating ERC20s into their DeFi tasks. For instance, you possibly can’t predict when and what number of tokens you’ll obtain while 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 examine how a lot cash is obtained. Should you’re aware of the Uniswap codebase, you in all probability know that the UniswapV2Pair contract has many balanceOf() calls.

Within the code snippet, 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 property (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 unhealthy actor can revenue when the rewards exceed the bills.

The UniswapV2Pair.burn() has an identical threat. The mint() operate caller may jeopardize himself and not using a 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 property (i.e., token0 and token1). Afterward, (amount0, amount1) of the 2 property 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() operate 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 unhealthy actor can revenue from doing this.

Loophole Evaluation: BunnyMinterV2

Within the PancakeBunny supply code, the BunnyMinterV2.mintForV2() operate is accountable for 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 a few capabilities: _zapAssetsToBunnyBNB() (line 213), priceCalculator.valueOfAsset() (line 219) and amountBunnyToMint() (line 221). For the reason that unhealthy 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() operate. 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 property 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()) can be despatched to the PancakePair contract (line 500) and PancakePair.burn() can be invoked. If the present LP token stability of PancakePair is larger than 0, the precise quantity to be burned can 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 change the 2 property collected by the removeLiquidity() into BUNNY-BNB LP tokens. Since zapBSC swaps property by way of PancakeSwap, the unhealthy actor might use flash loans to control the quantity of swapped BUNNY-BNB.

Again to BunnyMinterV2.mintForV2(), the bunnyBNBAmount returned by zapAssetsToBunnyBNB() can 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 allows the unhealthy actor to make use of flash loans to control the quantity of BUNNY tokens minted.

The amountBunnyToMint() operate 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 must be certified for rewards first.

As proven within the Etherscan screenshot above, the PancakeBunny hacker invoked the init() operate of the exploit contract to change 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() operate 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 in a position to get rewards till the PancakeBunny keeper triggers the subsequent 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 function 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 function to mortgage 2.3M WBNB:

handle[7] pairs = [

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 Zero or 1, that means we have to borrow token0 or token1.

Utilizing the callback operate pancakeCall(), we recursively name PancakePair.swap() with degree+1 till we attain the seventh degree. On the prime 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() operate 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 control the removeLiquidity() name contained in the _zapAssetsToBunnyBNB() operate as analyzed above, enabling us to obtain extra WBNB+USDT than anticipated.

The second step is to control the USDT value 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. Observe 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 straightforward 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 unhealthy actor pays 1 WBNB and walks away with 104okay WBNB + 3.8M USDT (equal to ~$45M).

About Amber Group

Amber Group is a number one world 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 companies over 500 institutional shoppers and has cumulatively traded over $500 billion throughout 100+ digital exchanges, with over $1.5 billion in property below administration. In 2021, Amber Group raised $100 million in Sequence B funding and have become the newest FinTech unicorn valued over $1 billion. For extra info, please go to: