Closed GrosQuildu closed 2 years ago
We just spent some time modeling this and found that in order for there to be a zero value returned, there has to be an expectedAmount of less than 0.000001 USDC. Now that we have added a reentrancy guard in the liquidatePortion
function, we believe it should be fine to leave the function as is.
During our discussion though we did discover something else that we would like to discuss with your team. Right now we use a custom oracle that wraps Chainlink (e.g. https://etherscan.io/address/0xF808ec05c1760DE4794813d08d2Bf1E16e7ECD0B#code)
It can be seen here that there is a manual override function that was put in place in case of an oracle outage: https://github.com/maple-labs/maple-core/blob/4577df4ac7e9ffd6a23fe6550c1d6ef98c5185ea/contracts/oracles/ChainlinkOracle.sol#L83
This was to protect against an oracle outage in the LoansV1 code, where we used the price to determine collateral amounts to post to meet a given collateral ratio and to determine the expected amount to be returned from the atomic UniswapV2 liquidation.
Now we are concerned that this actually opens up a new attack vector, where an attacker could "wrench attack" the owners of the security multisig keys and set the oracle price to zero manually in the oracle wrapper and drain all of the funds.
Two questions:
Description
In
getExpectedAmount
method,oracleAmount
is scaled from collateral's to fund's asset decimals. Similar scaling is done forminRatioAmount
- the_minRatio
value should be provided in funds asset's decimals precision, according to tests.If the
IERC20Like(collateralAsset).decimals()
is larger thanIERC20Like(fundsAsset).decimals()
andswapAmount_
is small enough, the numerators will be smaller than denominators in both equations, and the value returned from thegetExpectedAmount
will be 0.For an example, consider a case with USDC as funds asset and YAMv2 as collateral:
This bug may allow an attacker to drain Liquidator from collateral for "free" - especially if the additional gas cost is lower than the expected funds assets value.
Exploit Scenario
A loan with USDC as the funds asset and some token with 18 decimals as collateral asset is defaulted. An attacker repeatedly calls
liquidatePortion
method (e.g. using reentrancy from themsg.sender.call
invocation) from theLiquidator
contract with smallswapAmount
values. He repeatedly receives small amounts of collateral token, and don't have to send back any funding tokens, becausegetExpectedAmount
method keeps returning zero - due to the arithmetic precision bug.Recommendations
In
liquidatePortion
method, reject calls with smallswapAmount
s, or check if values returned fromgetExpectedAmount
don't equal to zero. Make sure that small amounts of collateral won't be locked in the contract.Alternatively, in
getExpectedAmount
check if value returned will be 0, and return 1 instead - forcing users to overpay for small liquidations.