code4rena-2024-03-dittoeth-h03
[H-03] Users can mint DUSD with less collateral than required, which gives them free DUSD and may open a liquidatable position
Summary
부분 매칭 상태의 숏 주문을 취소할 때, 매칭된 양이 최소량보다 적다면 부족분을 유저의 담보를 사용해 추가 매칭한다. 필요한 담보의 양을 계산할 때 유저가 통제 가능한 값을 사용하므로, 이를 조작하면 적은 담보로 더 많은 dUSD를 발행할 수 있다.
Keyword
logic flaw, lack of input validation, defi
Vulnerability
유저가 숏 주문을 취소할 때, 부분 체결된 숏의 체결량이 최소량보다 적다면 모자란 만큼을 추가로 체결하고 남은 양은 취소한다. 너무 작은 양의 숏이 남아있지 않도록 하기 위해 체결된 숏의 최소 크기를 보장하기 위함이다. 숏 주문을 취소하면 숏 주문 생성시 맡긴 담보 토큰(dETH)을 돌려받는다. 최소량보다 모자란 만큼 체결할 때는 이 담보 토큰을 사용한다.
다음 코드는 최소량보다 모자란 만큼을 추가로 체결하는 로직이다. debtDiff 는 최소량보다 모자란 양으로, 이만큼의 dUSD를 더 체결해야 한다. debtDiff 에 상응하는 담보 dETH의 양 collateralDiff 를 계산하여 숏 체결에 사용한다. 이 collateralDiff를 계산할 때 2가지 문제가 있다.
shortOrder.shortOrderCR를 사용해 담보 양을 계산한다. 이 값은 숏터가 부담할 담보율을 의미하며 숏 주문 생성시 숏터가 지정하는 값이다. 만약 숏 주문의 담보 비율이 100% 가 아니라면collateralDiff는debtDiffdUSD의 가치보다 작게 계산될 것이다. (shortOrderCR는 디폴트로 70% 이상으로 설정되어야 한다.shortOrderCR가 70이라면 정상 거래 시 100%는 유저의 구매금, 70%는 숏터의 담보 총합 170% 가치의 dETH가 담보로 묶인다.)shortOrder.price를 사용해 담보 양을 계산한다. 이 값은 숏터가 지정한 거래 가격이다. 만약 숏터가 실제보다 낮은 가격을 등록했다면 실제보다 적은 담보가 사용될 것이다.
즉, 최소량 부족분 자동 체결은 시세가 아닌 숏터가 제공한 값에 의존하여 이루어진다는 문제점이 있다.
...
@> uint88 debtDiff = minShortErc - shortRecord.ercDebt;
{
STypes.Vault storage Vault = s.vault[vault];
@> uint88 collateralDiff = shortOrder.price.mulU88(debtDiff).mulU88(LibOrders.convertCR(shortOrder.shortOrderCR));
LibShortRecord.fillShortRecord(
asset,
shorter,
shortRecordId,
SR.FullyFilled,
collateralDiff,
debtDiff,
Asset.ercDebtRate,
Vault.dethYieldRate
);
Vault.dethCollateral += collateralDiff;
Asset.dethCollateral += collateralDiff;
Asset.ercDebt += debtDiff;
// @dev update the eth refund amount
eth -= collateralDiff;
}
// @dev virtually mint the increased debt
s.assetUser[asset][shorter].ercEscrowed += debtDiff;
...악성 유저는 다음과 같이 악용할 수 있다.
shortOrderCR를 100%보다 낮게 설정하여 숏 주문을 만든다.- 해당 주문이 부분 매칭되도록 한다.
- 숏 주문을 취소하여 dUSD를 시세보다 저렴하게 민팅한다.
Impact
제공한 담보의 가치보다 많은 dUSD를 발행할 수 있다.
Mitigation
최소량 부족분 구매 시 오라클에서 가져온 현재 가격을 사용한다. shortOrder.shortOrderCR < initialCR 라면 initialCR 를 대신 사용한다. 이렇게 변경하면 기존에 맡겼던 dETH 담보가 모자라 숏 주문을 닫을 수 없는 상황이 생길 수 있다. 이를 대비하여 추가금을 받는 것을 고려하라.
Memo
유사한 이슈가 DittoETH의 다음 오딧에서도 다시 나타났다.
tags: bughunting, dittoeth, smart contract, solidity, logic flaw, lack-of-input-validation-vul, defi, severity high