sherlock-audit / 2023-10-aloe-judging

9 stars 6 forks source link

OxZ00mer - The whole ante balance of a user with a very small loan, who is up for liquidation can be stolen without repaying the debt #146

Open sherlock-admin opened 1 year ago

sherlock-admin commented 1 year ago

OxZ00mer

high

The whole ante balance of a user with a very small loan, who is up for liquidation can be stolen without repaying the debt

Summary

Users with very small loans on markets with tokens having very low decimals are vulnerable to having their collateral stolen during liquidation due to precision loss.

Vulnerability Detail

Users face liquidation risk when their Borrower contract's collateral falls short of covering their loan. The strain parameter in the liquidation process enables liquidators to partially repay an unhealthy loan. Using a strain smaller than 1 results in the liquidator receiving a fraction of the user's collateral based on collateral / strain.

The problem arises from the fact that the strain value is not capped, allowing for a potentially harmful scenario. For instance, a user with an unhealthy loan worth $0.30 in a WBTC (8-decimal token) vault on Arbitrum (with very low gas costs) has $50 worth of ETH (with a price of $1500) as collateral in their Borrower contract. A malicious liquidator spots the unhealthy loan and submits a liquidation transaction with a strain value of 1e3 + 1. Since the strain exceeds the loan value, the liquidator's repayment amount gets rounded down to 0, effectively allowing them to claim the collateral with only the cost of gas.

assembly ("memory-safe") {
    // ...
    liabilities0 := div(liabilities0, strain) // @audit rounds down to 0 <-
    liabilities1 := div(liabilities1, strain) // @audit rounds down to 0 <-
    // ...
}

Following this, the execution bypasses the shouldSwap if-case and proceeds directly to the following lines:

// @audit Won't be repaid in full since the loan is insolvent
_repay(repayable0, repayable1);
slot0 = (slot0_ & SLOT0_MASK_POSITIONS) | SLOT0_DIRT;

// @audit will transfer the user 2e14 (0.5$)
payable(callee).transfer(address(this).balance / strain);
emit Liquidate(repayable0, repayable1, incentive1, priceX128);

Given the low gas price on Arbitrum, this transaction becomes profitable for the malicious liquidator, who can repeat it to drain the user's collateral without repaying the loan. This not only depletes the user's collateral but also leaves a small amount of bad debt on the market, potentially causing accounting issues for the vaults.

Impact

Users with small loans face the theft of their collateral without the bad debt being covered, leading to financial losses for the user. Additionally, this results in a potential amount of bad debt that can disrupt the vault's accounting.

Code Snippet

https://github.com/sherlock-audit/2023-10-aloe/blob/main/aloe-ii/core/src/Borrower.sol#L194

https://github.com/sherlock-audit/2023-10-aloe/blob/main/aloe-ii/core/src/Borrower.sol#L283

Tool used

Manual Review

Recommendation

Consider implementing a check to determine whether the repayment impact is zero or not before transferring ETH to such liquidators.

require(repayable0 != 0 || repayable1 != 0, "Zero repayment impact.") // @audit <-
_repay(repayable0, repayable1);

slot0 = (slot0_ & SLOT0_MASK_POSITIONS) | SLOT0_DIRT;

payable(callee).transfer(address(this).balance / strain);
emit Liquidate(repayable0, repayable1, incentive1, priceX128);

Additionally, contemplate setting a cap for the strain and potentially denoting it in basis points (BPS) instead of a fraction. This allows for more flexibility when users intend to repay a percentage lower than 100% but higher than 50% (e.g., 60%, 75%, etc.).

sherlock-admin2 commented 1 year ago

2 comment(s) were left on this issue during the judging contest.

panprog commented:

low, because it's more profitable to just straight liquidate fully, besides the loss per transaction will be very small

MohammedRizwan commented:

valid

Shogoki commented 1 year ago

Escalate I think this is a Low issue. The attack is not profitable, it would probably be more profitable to straight liquidate the position. Therefore a liquidation bot would probably do that.

In case of the ANTE the user looses, i would not consider it a real loss, as it is expected he has to pay it for liquidation anyhow.

sherlock-admin2 commented 1 year ago

Escalate I think this is a Low issue. The attack is not profitable, it would probably be more profitable to straight liquidate the position. Therefore a liquidation bot would probably do that.

In case of the ANTE the user looses, i would not consider it a real loss, as it is expected he has to pay it for liquidation anyhow.

You've created a valid escalation!

To remove the escalation from consideration: Delete your comment.

You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.

KristianApostolov commented 1 year ago

The vector above is profitable under the stated assumptions It demonstrates that the attacker does not need to pay off any of the debt of the victim, but can freely take the ante without paying for anything else than the gas for the transaction, hence they profit without completing the action and stealing the funds from the victim, but leaving them with unpaid debt.

Oot2k commented 1 year ago

Agree with escalation

cvetanovv commented 1 year ago

I disagree with the escalation and this report should remain a valid Medium. The Sponsor also confirms that this is a valid Medium. Although unlikely to be exploited this way due to the opportunity cost, Watson correctly demonstrates how this can be a profitable attack vector.

Czar102 commented 1 year ago

Result: Medium Unique

A bug that inflicts a loss to the attacker but also compromises the system is a valid medium.

sherlock-admin2 commented 1 year ago

Escalations have been resolved successfully!

Escalation status:

haydenshively commented 12 months ago

Fixed in https://github.com/aloelabs/aloe-ii/pull/223

roguereddwarf commented 12 months ago

Mitigation Review:

The ante is only paid out when the Borrower ends up healthy or is insolvent. In the case that the Borrower is not insolvent, the liquidator only receives the same share of the ante by which he has reduced the liabilities. Thereby it's no longer possible to receive the ante without actually repaying any debt (or erasing the debt). In other words, a liquidator that does not contribute to the liquidation does not receive any of the ante.