codehawks-2023-07-dsc-h02
[H-02] Liquidation Is Prevented Due To Strict Implementation of Liqudation Bonus
Summary
liquidate 시 10%의 보너스로 인해 담보가 100-110% 사이일 때 예치된 담보 토큰 양보다 많은 양의 토큰을 주려고 하여 언더플로우가 발생한다. 이로 인해 트랜잭션이 revert 되므로 담보 비율이 100-110% 사이일 때는 청산시킬 수 없다.
Keyword
integer underflow, bug, logic flaw
Vulnerability
담보 토큰의 가격이 떨어져서 유저의 담보가 200% 과담보 아래로 떨어지면 아무나 liquidate 함수를 호출해 자신의 DSC 토큰을 소각하며 해당 유저(이하 유저A)의 담보를 청산할 수 있다.
liquidate 함수 호출자는 소각한 DSC의 가치만큼의 담보 토큰을 얻으며 추가로 10%의 보너스 담보 토큰을 더 얻을 수 있다.
하지만 이는 유저A의 담보율이 100-110% 사이일 때는 동작하지 않을 수 있다. 유저A가 예치한 담보 내에서 청산해야 하는데, 보너스 10%까지 합쳤을 때 유저A의 담보 토큰 양보다 함수 호출자에게 줘야하는 토큰의 수가 많아질 수 있기 때문이다.
_redeemCollateral 함수의 s_collateralDeposited[from][tokenCollateralAddress] -= amountCollateral; 에서 유저A가 예치한 담보 토큰보다 많은 양의 토큰을 꺼내가려 시도하므로 언더플로우가 발생, 트랜잭션이 revert 된다.
function liquidate(address collateral, address user, uint256 debtToCover)
external
moreThanZero(debtToCover)
nonReentrant
{
// need to check health factor of the user
uint256 startingUserHealthFactor = _healthFactor(user);
if (startingUserHealthFactor >= MIN_HEALTH_FACTOR) {
revert DSCEngine__HealthFactorOk();
}
@> uint256 tokenAmountFromDebtCovered = getTokenAmountFromUsd(collateral, debtToCover);
@> uint256 bonusCollateral = (tokenAmountFromDebtCovered * LIQUIDATION_BONUS) / LIQUIDATION_PRECISION;
@> uint256 totalCollateralToRedeem = tokenAmountFromDebtCovered + bonusCollateral;
@> _redeemCollateral(user, msg.sender, collateral, totalCollateralToRedeem);
_burnDsc(debtToCover, user, msg.sender);
uint256 endingUserHealthFactor = _healthFactor(user);
if (endingUserHealthFactor <= startingUserHealthFactor) {
revert DSCEngine__HealthFactorNotImproved();
}
_revertIfHealthFactorIsBroken(msg.sender);
}
function _redeemCollateral(address from, address to, address tokenCollateralAddress, uint256 amountCollateral)
private
{
@> s_collateralDeposited[from][tokenCollateralAddress] -= amountCollateral;
emit CollateralRedeemed(from, to, tokenCollateralAddress, amountCollateral);
bool success = IERC20(tokenCollateralAddress).transfer(to, amountCollateral);
if (!success) {
revert DSCEngine__TransferFailed();
}
}Impact
담보 비율이 위험 범위로 떨어지더라도 담보의 완전한 청산은 피할 수 있으며, 이는 프로토콜의 안정성과 보안에 문제가 된다.
Mitigation
담보가 100-110% 사이일 때는 10%의 보너스를 주는 대신, 최대로 줄 수 있는 양인 유저A의 예치량까지만 지급하도록 제한한다.
uint256 totalDepositedCollateral = s_collateralDeposited[user][collateral];
if (tokenAmountFromDebtCovered < totalDepositedCollateral && totalCollateralToRedeem > totalDepositedCollateral) {
totalCollateralToRedeem = totalDepositedCollateral;
}tags: bughunting, codehawks, smart contract, solidity, integer overflow underflow, logic flaw, severity high