code4rena-2023-06-angle-protocol-m02
[M-02] Unsafe cast in getCollateralRatio()
Summary
엣지케이스에서 캐스팅으로 인해 collatRatio 값이 절삭되어 잘못된 비율을 기반으로 계산하게 된다.
Keyword
overflow/underflow, casting
Vulnerability
// The `stablecoinsIssued` value need to be rounded up because it is then used as a divizer when computing
// the amount of stablecoins issued
stablecoinsIssued = uint256(ts.normalizedStables).mulDiv(ts.normalizer, BASE_27, Math.Rounding.Up);
if (stablecoinsIssued > 0)
collatRatio = uint64(totalCollateralization.mulDiv(BASE_9, stablecoinsIssued, Math.Rounding.Up)); //@audit unsafe cast
else collatRatio = type(uint64).max;일반적으로 collatRatio 는 BASE_9 근처 값이어야 하지만, 초기에는 type(uint64).max보다 클 수도 있다.
또한 totalCollateralization는 담보물의 실제 잔액을 사용해 계산하며, stablecoinsIssued가 크지 않다면 조작될 수도 있다. stablecoinsIssued가 1 wei면 1 USD로 충분하다고 한다. collatRatio = 1 * 1e18 (=1 USD) * 1e9 / 1 wei = 1e27 이고, 1e27 > 2^64 이므로 절삭된다.
function getCollateralRatio()
internal
view
returns (
uint64 collatRatio,
uint256 stablecoinsIssued,
address[] memory tokens,
uint256[] memory balances,
uint256[] memory subCollateralsTracker
)
{
...
{
...
for (uint256 i; i < collateralListLength; ++i) {
...
uint256 collateralBalance; // Will be either the balance or the value of assets managed
if (collateral.isManaged > 0) {
...
(subCollateralsBalances, collateralBalance) = LibManager.totalAssets(collateral.managerData.config);
...
} else {
collateralBalance = IERC20(collateralList[i]).balanceOf(address(this));
...
}
uint256 oracleValue = LibOracle.readRedemption(collateral.oracleConfig);
totalCollateralization +=
(oracleValue * LibHelpers.convertDecimalTo(collateralBalance, collateral.decimals, 18)) /
BASE_18;
}
}
stablecoinsIssued = uint256(ts.normalizedStables).mulDiv(ts.normalizer, BASE_27, Math.Rounding.Up);
if (stablecoinsIssued > 0)
collatRatio = uint64(totalCollateralization.mulDiv(BASE_9, stablecoinsIssued, Math.Rounding.Up));
else collatRatio = type(uint64).max;
}이 경우 collatRatio는 uint64 캐스팅으로 인해 절삭되고, getCollateralRatio가 잘못된 비율을 반환하면 프로토콜에 심각한 영향을 끼칠 것이다.
Impact
캐스팅으로 인해 collatRatio 값이 절삭되어 잘못된 비율을 기반으로 계산하게 된다.
Mitigation
SafeCast 라이브러리를 사용하여 캐스팅으로 인해 절삭된 상황에서 거래하는 것을 방지한다.
Memo
프로젝트 측은 비현실적인 케이스라고 심각도를 낮추려 했다. 심판 측은 그럼에도 getCollateralRatio 함수가 프로토콜에서 중요한 역할을 하므로 Medium으로 쳤다.
tags: bughunting, angle protocol, smart contract, solidity, stablecoin, casting overflow underflow, severity medium