Open c4-bot-2 opened 8 months ago
GalloDaSballo marked the issue as primary issue
GalloDaSballo marked the issue as sufficient quality report
edge case if user is about to be liquidated I think they will make things collateralized to avoid liquidation, either way we would like to see this as medium. fix already applied. this is also something that been explored in hats.finance competition hence 564-566 lines came from there etc.
High is appropriate, especially with the PoC demonstrated.
trust1995 marked the issue as selected for report
For transparency and per conversation with the sponsors, see here for the Wise Lending team's mitigation.
Lines of code
https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseSecurity/WiseSecurityHelper.sol#L760-L786 https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseSecurity/WiseSecurityHelper.sol#L206-L208 https://github.com/code-423n4/2024-02-wise-lending/blob/79186b243d8553e66358c05497e5ccfd9488b5e2/contracts/WiseCore.sol#L564-L586
Vulnerability details
Vulnerability Description
When a user deposits in the Wiselending contract he can make a private deposit (pure) which allows his deposits not to be used as collateral or a normal deposit. He can also set his position to be collateralized or uncollateralized. If a position is collateralized, the normal deposit can be used as collateral and vice-versa.
When a user uncollateralizes his position, he can only use his private deposit as collateral. If the position becomes liquidatable, it means the private deposit can no longer cover the amount borrowed. In the call to
getFullCollateralETH()
below only the private collateral is returned immediately as full collateral if it is uncollateralized.WiseSecurityHelper.sol#L198-L208
In a liquidation, the amount to be liquidated is expressed as a percentage of the full collateral. In an uncollateralized position, the full collateral is the private collateral. The
calculateWishPercentage()
call calculates this percentage.WiseSecurityHelper.sol#L760-L786
The amount to be liquidated i.e the amount the liquidator receives is calculated in
_calculateReceiveAmount()
using the percentage fromcalculateWishPercentage()
and applied to the position's pure collateral first in line 557 below.It calculates the percentage of the user's normal balance to be reduced in line 569 without checking if it is uncollateralized. If the amount it gets i.e
potentialPureExtraCashout
is greater than zero and less than the current private balance (pureCollateral
) in line 576, it is reduced from the private balance.WiseCore.sol#L564-L586
The issue is the implementation applies the percentage meant for only the private collateral to both the normal and private collateral. It should reduce only the private collateral, but may also reduce the public collateral and send it to the liquidator.
Here's how a malicious liquidator can profit and steal user funds:
A liquidator can set it up to drain the private collateral balance and only pay for a portion of the liquidation. The user ends up losing funds and the protocol's bad debt increases.
Impact
This vulnerability allows the liquidator to steal the user's balance and pay for only a portion of the shares. It has these effects:
Proof of Concept
The
testStealPureBalance()
test below shows a liquidator earning more than the amount he paid for liquidation. The test can be put in any test file in the contracts directory and run there.Tools Used
Manual Analysis
Recommended Mitigation Steps
To ensure the code does not also consider the normal balance at all we can check if the position is uncollateralized early. Currently, this check is done but is done too late in the
_calculateReceiveAmount()
function. We can fix it by moving the check.WiseCore.sol#L560-L594
Assessed type
Invalid Validation