How To Stole An Election: BeanStalk DAO $80million FlashLoan Attack Study Case.
Credit: Khang Hoang, Giap Nguyen
Summary
On 17/04/2022, a hacker performed a brilliant attack against the Defi DAO BeanStalk. By leveraging the flash loan mechanism, the hacker made a $1b loan (YES, $1,000,000,000 LOAN) to gather 80% of the voting power of BeanStalk DAO. Then the hacker self-voted his malicious smart contract to replace the DAO governance. Finally, he was able to drain the whole project's pool of about 24,830 ETH and 36M BEAN - to cause a total $80m loss.
In this study case, we analyze the hacking technique, the vulnerable DAO implementation and offer our recommendation.
What is a Flash Loan?
The first thing that makes you pull your hair out is how the hacker was able to loan $1b without any collateral!!! All heil the Crypto Gods, anyone understand the flash loan mechanism could to do that without any risk.
Essentially, the flash loan transaction involves at least 3 smart contracts:
The lender smart contract lends money to the borrower smart contract.
The borrower calls other smart contracts with the money.
The borrower gets the money back.
The borrower repays the money + interest to the lender.
The lender checks the money return with interest to finalize the transaction. If the borrower can not repay the right amount of money, the lender undo everything including whatever the borrower did with the money.
The magic happens because the Ethereum VM will process all of 4 steps at once. If one step failed, everything reverted as if nothing happened.
The template code
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external override returns (bool){
…
require(
receiver.onFlashLoan(msg.sender, token, amount, fee, data) == CALLBACK_SUCCESS,
"FlashMinter: Callback failed"
);
uint256 _allowance = allowance(address(receiver), address(this));
require(
_allowance >= (amount + fee),
"FlashMinter: Repay not approved"
);
…
return true;
}
The first requirement makes sure the borrower consumes the money and the second makes sure the money and interest is collected.
The BeanStalk DAO
We can see that the BeanStalk DAO is designed as a decentralized stable coin. Using a transitive relation between the Uniswap liquidity pool (LP) ETH:USDC and their own Uniswap LP ETH:Bean, BeanStalk can maintain a peg 1 Bean with 1 USDC.
The BeanStalk DAO is complicated, but we will just focus on their Governance contract and Silo contract.
Silo Contract
Silo Contract is for stalking BEAN and BEAN LP tokens such as BEAN/ETH-LP and BEAN/3CRV-f, BEAN/LUSD-f.
The rationale for allowing stalking LP tokens based on Bean proposal:
Adding the BEAN:LUSD Curve pool to the Silo whitelist is beneficial to the success of both Beanstalk and Liquidity. While the Silo’s yield should attract initial capital to the pool, the Stalk and Seed system incentivizes long-term liquidity that helps to further stabilize the prices of both BEAN and LUSD. (https://github.com/BeanstalkFarms/Beanstalk/blob/master/bips/bip-16.md)
The stalking LP also earn Stalk and Seed for voting the DAO governance changes
Stalk per BDV: 1 Stalk per BDV.
Seeds per BDV: 3 Seeds per BDV. (https://github.com/BeanstalkFarms/Beanstalk/blob/master/bips/bip-16.md)
The last thing sounds alarm for those who understand the concept of floating shares in the stock market. If the floating shares overwhelmed the authoritative shares, one is able to buy or borrow enough votes to take over the public company for their profit.
In the blockchain world, the LP tokens are perfect targets for flashloan strategy. This can be done without collateral, and also risk free. In the worst case, the attacker only loses a tiny transaction fee if he fails to make profit from the attack.
Governance Contract
The contract serves provisioning and implementing BeanStalk Improvement Proposal (BIP) is available at https://github.com/BeanstalkFarms/Beanstalk/tree/master/bips.
The BIP mechanism explained in is available at https://github.com/BeanstalkFarms/Beanstalk/blob/master/bips/bip-1.md
Proposing:
Anyone with more than 2,500 Stalk can make a budget proposal. We want proposing allocations of the budget to be widely accessible to Farmers of all sizes.
Proposition must be made on the official Beanstalk Farms Snapshot group, and must use the recent Ethereum block as the Snapshot block.
Proposals to allocate funds must include the recipient, amount, duration of the payments, what is expected to be covered by the allocation and any other relevant details.
Voting:
Any Stalk holder can vote for or against any of the Snapshot proposals. In all instances, 1 Stalk equals 1 vote.
The amount of Stalk each account has is determined at the time a proposal is submitted.
In order to be counted, votes must be placed before the proposal ends.
The proposal was submitted as an arbitrary smart contract. At the end of success voting, the smart contract will replace the DAO functions.
It is interesting that BIP-1 also implements a shortcut for an arbitrary smart contract to be triggered immediately without having to wait for a vote.
Passing:
In order to pass, a proposal must receive a quorum of 1/3 of all Stalk at the time the proposal is submitted.
In order to pass, a proposal must receive > 50% of votes in favor at the time it ends.
If > 50% of all Stalk at the time of submission vote in favor of a proposal it instantly passes.
The Vulnerability
Given public liquidity tokens have voting power, the attacker was able to make a flash loan to earn a massive amount of Stalk. By taking advantage of the passing rules, he could trigger his malicious smart contract immediately. Then he stole the whole BEAN $80m pool and returned the $1bn loan + $1 million interest. Everything happened in a single transaction.
In fact, this vulnerability was already reported by a Bean user (and we hope he is not the attacker): on 13/02/2022, @MrMochi raised the issue but unfortunately the admin ignored it
It looks like someone took a note and planned the attack.
The Attack Detail
The hacker’s wallet: 0x1c5dCdd006EA78a7E4783f9e6021C32935a10fb4
The hacker malicious proposal BIP-18: 0xE5eCF73603D98A0128F05ed30506ac7A663dBb69
The hacker flash loan smart contract: 0x79224bC0bf70EC34F0ef56ed8251619499a59dEf
Step 1: Submit the malicious proposal.
Swap 73 ETH to 212,858 BEAN vs Uniswap V2: https://etherscan.io/tx/0xfdd9acbc3fae083d572a2b178c8ca74a63915841a8af572a10d0055dbe91d219
Deposit BEAN into Silo to meet requirement for submit BIP: https://etherscan.io/tx/0xf5a698984485d01e09744e8d7b8ca15cd29aa430a0137349c8c9e19e60c0bb9d
Call the “propose” function of Governance to add the malicious BIP. Recorded as BIP-18: 0x68cdec0ac76454c3b0f7af0b8a3895db00adf6daaf3b50a99716858c4fa54c6f
Step 2: Perform a nested flash loan attack (20 steps in a single tx)
0xcd314668aaa9bbfebaf1a0bd2b6553d01dd58899c508d4729fa7311dc5d33ad7
Loan 350m DAI, 500m USDC, 150m USDT from AAVE and 32.2m BEAN from Uniswap and 11.6m LUSD from SushiSwap
Add liquidity 350m DAI + 500m USDC + 150m USDT into Curve.fi to mint 979.7m token 3Crv.
Swap 15m 3Crv to 15.25m LUSD from Curve.fi
Now he gather total:
964.7m 3Crv
32.2m BEAN
26.9m LUSD
Add liquidity into pool BEAN/3CRV to swap 964.7m token 3Crv into 795.4m LP token BEAN3CRV-f
Now he have:
795.4m BEAN3CRV-f
32.2m BEAN
26.9m LUSD
Add liquidity to pool BEAN/LUSD to swap 32.2m BEAN và 26.9 LUSD into 58.9m LP token BEANLUSD-f
Now he completely control all BEAN LP tokens from Curve.fi which count of 80% voting power (notice BEAN/ETH-LP token still out of hacker control ) :
795.4m BEAN3CRV-f
58.9m BEANLUSD-f
Staking 795.4m BEAN3CRV-f and 58.9m BEANLUSD-f into Silo.
Call contract Governance to open voting round for BIP-18
Call
emergencyCommit
function which executes passing rule. Theinit
function of contract BIP-18 was automatically executed and drained everything from BeanStalk Protocol contract.Now hacker owned:
36m BEAN
874.6m BEAN3CRV-f
60.5m BEANLUSD-f
0.54 UNI-V2 BEAN/WETH LP token
Remove liquidity from pool BEAN/3CRV to swap 874.6m BEAN3Crv-f to 1.0B 3Crv
36m BEAN
1.0B 3Crv
60.5m BEANLUSD-f
0.54 UNI-V2 BEAN/WETH LP token
Remove liquidity from pool BEAN/LUSD swap 60.5m BEANLUSD-f to 28.1m LUSD
36m BEAN
1.0B 3Crv
28.1m LUSD
0.54 UNI-V2 BEAN/WETH LP token
Repay 11.7m LUSD for SushiSwap and 32.2m BEAN for Uniswap (interest included).
3.9m BEAN
1.0B 3Crv
16.4m LUSD
0.54 UNI-V2 BEAN/WETH LP token
Swap 16.4m LUSD to 16.2m 3Crv vs pool LUSD/3CRV.
3.9m BEAN
1,007.7 3Crv + 16.2m 3Crv
0.54 UNI-V2 BEAN/WETH LP token
Remove liquidity from DAI/USDC/USDT master Curve.fi pool:
Swap 511.9m 3Crv to 522.5m USDC
Swap 358.4m 3Crv to 365.7m DAI
Swap 153.6m 3Crv to 156.7m USDT
Now he owned:
3.9m BEAN
522.5m USDC
365.7m DAI
156.7m USDT
0.54 UNI-V2 BEAN/WETH LP token
Repay Aave protocol flash loan + interest. 350.315m DAI, 500.450m USDC, 150.135m USDT
Now he owned
3.9m BEAN
15.4m DAI
22m USDC
6.59m USDT
0.54 UNI-V2 BEAN/WETH LP token
Remove liquidity from pool BEAN/ETH of Uniswap, exchange 0.540 UNI-V2 BEAN/WETH into 10,883 WETH and 32.5m BEAN.
Now he owned:
36.4m BEAN
15.4m DAI
22m USDC
6.59m USDT
10,883 WETH
Send 250k USDC to Ukraine Crypto Donation
Swap 15.4m DAI to 15.4m USDC
The hacker’s wallet:
36.4m BEAN
37.2m USDC
6.6m USDT
10,883 WETH
Swap 37.2m USDC to 11,822 WETH
Swap 6.6m USDT o 2,124 WETH
Now hacker completely convert all stable coins into WETH:
36.4m BEAN
24,830 WETH
Withdraw 24,830 WETH into 24,830 ETH into the hacker's wallet, 0x1c5dCdd006EA78a7E4783f9e6021C32935a10fb4
The BeanStalk admin burnt all hacker's BEAN after that.
Summary: The hacker made a flash loan $1billion; performed a complex attack to gather 80% voting power and drain everything from the DAO smart contracts. He returned $1b loan + $1m interest and made 24,830 eth ~ $74,5m. The exploitation happens in a single transaction
Our recommendation
In Verichains, we have been designing and auditing DAO for a long time. We conclude that it is hard to secure complex DAOs and upgradable DAOs are very dangerous. It is always transparent and trustable if you are able to understand how a DAO works and ensure it does not suddenly change without your notice.
Be careful with distribution of voting power. It is dangerous for any democracy system if massive votes are available for hiring. The current Defi ecosystem is incentivized for everyone to stalk or loan their crypto assets. So the assumption that those who own a high amount of Stalk does no harm is not correct.
Risk management in Defi is a must-have; it is bad to implement a system that allows to drain all the assets in a single transaction. This should never happen in a real finance institution with a proper risk management design.