From Apr-30–2022 09:01:35 AM +UTC to Apr-30–2022 09:35:24 AM +UTC, Fei Protocol announced that they were aware of and looking into an exploit on various Rari Fuse pools. The total loss currently reported is ~$80 Million. They have paused all borrowing to minimize further loss.
The root cause of this attack stems from a Reentrancy security loophole where an attacker is able to borrow assets yet withdraw all the deposited collateral. Specifically, the attacker flashloaned multiple tokens/WETH as collateral and borrowed assets from the pool. However, as the code implementation does not apply the practice of the check-effect-interaction pattern, the result means that the attacker can invoke “exitMarket()” to withdraw all his collateral as the borrow records are not properly updated.
- FEI protocol is an algorithmic stable coin project for decentralized finance. Fei Protocol aims to help other DAOs achieve deep liquidity in lending and exchange markets by deploying PCV and offering Liquidity-as-a-Service (LaaS)
- Rari Fuse Pool is a DeFi protocol that facilitates lending, borrowing and creating isolated lending markets with unlimited flexibility.
Attacker address: 0x6162759edad730152f0df8115c698a42e666157f
Attacker contracts :
All relevant transactions can be found here: https://etherscan.io/address/0x6162759edad730152f0df8115c698a42e666157f
The section contains step-by-step information about how this exploit is perpetrated. Note that the attack flow is simplified here for ease of explanation.
The attack flow analysis used the following transaction on Ethereum network as example: 0xab486012f21be741c9e674ffda227e30518e8a1e37a5f1d58d0b0d41f6e76530
The attacker takes the advantage of the Reentrancy loophole of the protocol and performed the following actions:
- Attacker flashloaned 150,000,000 USDC and 50,000 WETH
- Deposited 150,000,000 USDC as collateral into the fUSDC-127 contract, which is a vulnerable fork version of the compound protocol.
- With deposited collateral, the attacker borrowed 1,977 ETH via the “borrow()” function.
- However, the “borrow()” function does not follow the check-effect-interaction pattern. Specifically, it transfers ETH to the attacker’s contract before updating the attacker’s actual borrow records.
- Therefore, with the attacker’s borrow record not updated, the attacker made a reentrant call to “exitmarket()” in the fallback function, which allows the attacker to withdraw all his collateral (150M USDC)
- The attacker repeated steps 1~5 on multiple other tokens.
- Finally, the attacker repaid the flashloan and transferred the rest to their address as profit, and routed some of the funds onward to Tornado Cash.
This attack was due to a design flaw in the FeiProtocl that failed to follow the check-effect-interaction pattern and thus allow the attacker to make a reentrant call before the borrow records are updated. In the “borrow()” function, the following code is implemented:
As the code illustrates, the “doTransferOut()” is invoked before the borrow records (i.e., “accountBorrows” and “totalBorrows” ) are updated.
The “doTransferOut()” function transfers ETH to the receiver via a low-level call:
Therefore, the attacker is able to make a reentrant call in the “fallback()” function to “exitMarket()”.
Profit and assets tracing
The illustrated diagram below is from the Skytrace to illustrate the attacker address movement of funds: https://www.certik.com/skytrace/eth:0x6162759edad730152f0df8115c698a42e666157f
Can the issue be found in the audit?
This issue can be found during the audit process. Security Professionals should be able to notice the following concerns during the audit process:
- A low-level call is invoked to transfer ETH.
- The code in the “borrow” logic violates the check-effect-interaction pattern.
The root cause of the Fei protocol exploit is the lack of a reentrancy protection mechanism implemented in the protocol. This is one of the well-known issues for this type of protocol, and this issue has been exploited or revealed prior to this incident but is still ignored by other similar protocols.
To learn more about the re-entrancy attack, CertiK recently shared a re-entrancy attack explainer article, which can be found here: https://certik.medium.com/what-is-a-reentrancy-attack-6516fefc001.
Below are a few of the recommendations for such a vulnerability:
- Strictly follow the check-effect-interaction pattern.
- Re-entrancy protection modifier should cover all corresponding functions.
- Introduce a third-party audit service to review the codebase.