28546 - [SC - Insight] FlashLoan can be taken with no fee to be paid
Submitted on Feb 20th 2024 at 16:02:57 UTC by @OceanAndThunders for Boost | eBTC
Report ID: #28546
Report type: Smart Contract
Report severity: Insight
Target: https://github.com/ebtc-protocol/ebtc/blob/release-0.7/packages/contracts/contracts/ActivePool.sol
Impacts:
Protocol insolvency
Description
Brief/Intro
The bug does not involve direct theft of funds, but it is a violation of how the the contract is meant to operate, it's exploitation can make the protocol offers flashloans without getting the fees of the loan back from users
Vulnerability Details
The contract "ActivePool" is meant to offer flash loan for the collateral token for users via the ActivePool.flashLoan
function, well for the users to have a flashloan they must on the callback sends back the borrowed assets of address(collateral)
with the calculated fees via flashFees(address(collateral, amount))
see on "https://github.com/ebtc-protocol/ebtc/blob/release-0.7/packages/contracts/contracts/ActivePool.sol?utm_source=immunefi"
The fee is claculated via the flashFee function, this function calculates the fees based on the given amount as :
The problem is that when amount
+ feeBps
are under MAX_BPS, (MAX_BPS > amount + feeBps) where the numerator is less than the denominator it will returns fractions like 0,3 ...etc, fractions will be considered 0 in solidity, thus the fee payment will be 0
as for example if consider calling the actual ActivePool in production (0x1e3Bf0965dca89Cd057d63c0cD65A37Acf920590) we will see that the feeBps
is 3 and MAX_BPS
is actually 10000, so any number that is under or equal to MAX_BPS / feeBps (3333) will returns it's fees as 0 !
use the following truffle (combine it with Ganache) Poc
shows "0x1e3Bf0965dca89Cd057d63c0cD65A37Acf920590" how it returns 0 as fees for amount of 3333 or under
means that for any number that is/or under 3333 we pay no fees
That was the first issue
Secondly the function is not protected against reentrancy attacks ! when a malicious actor that re-enters the ActivePool.flashLoan function 10 times on the "onFlashLoan" call with amount as 3333, he will get a flash loan of 33330 with 0 fees ! while the protocol was supposed to get 9 fees on it !
Impact Details
Combination of both can lead to the protocol being providing a flash loan of any number without getting any fees back, the attacker will consider paying only the high gas fees and not actually paying fees to ActivePool, those fees are the actual profit of the protocol, the existence of the bug means no profit for the protocol !
Proof of Concept
ActivePool is deployed on mainnet at "0x1e3Bf0965dca89Cd057d63c0cD65A37Acf920590"
use the following truffle (combine it with Ganache) Poc
shows "0x1e3Bf0965dca89Cd057d63c0cD65A37Acf920590" how it returns 0 as fees for amount of 3333 or under
means that for any number that is/or under 3333 we pay no fees
PoC of truffle :