- Type: Exploit
- Network: Mainnet
- Total lost: ~$6MM in various tokens
- Category: Reentrancy
- Exploited contracts:
- Attack transactions:
- Attack Block:: 15941674
- Date: Nov 10, 2022
- Reproduce:
forge test --match-contract Exploit_DFXFinance -vvv
- Request a Flashloan
- Deposit the received amount in the loan callback
As there is no reentrancy protection in the flashloan function and token balances are checked to determine if the loan was paid back, the attacker simply asked for a loan and deposited the amount requested to mint shares inside the loan callback.
function flash(
address recipient,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external transactable noDelegateCall isNotEmergency {
...
...
uint256 balance0After = IERC20(derivatives[0]).balanceOf(address(this));
uint256 balance1After = IERC20(derivatives[1]).balanceOf(address(this));
require(balance0Before.add(fee0) <= balance0After, 'Curve/insufficient-token0-returned');
require(balance1Before.add(fee1) <= balance1After, 'Curve/insufficient-token1-returned');
}
Because the balance checked after executing the flashloan callback was satisfied, the loan succeded. Then, the attacker simply called withdraw and stole the loan amount.
- Use reentrancy protection for flashloans
- Check if the flashloan key checks could be manipuladed by side-entering the contract and if so, evaluate its impact. Whenever a risk arises, add a reentrancy mutex to the vulnerable functions and to the flashLoan itself.