code4rena-2024-03-dittoeth-m09

[M-09] Valid redemption proposals can be disputed when bad debt occurs by applying it to a SR outside of the proposal

보고서

Summary

담보율을 낮추는 함수가 업데이트 시점을 기록하지 않아 청산 요청 이후에 업데이트 된 숏을 이의제기에 사용할 수 있다. 공격자가 청산을 취소시키고 수수료를 얻거나, 자신의 숏이 청산되지 않도록 하거나, 청산을 방해하여 디페깅을 유발할 수 있다.

Keyword

logic flaw, wrong state

Vulnerability

불량채권이 발생하면 모든 숏의 ercDebtRate 를 증가시켜 모두가 불량채권으로 인한 패널티를 부담한다. 숏 변제 중 갚을 수 없는 부채가 있다면 ercDebtRate를 증가시킨다. 그리고 숏을 종료하는 등 숏의 담보율에 변화가 생기는 상호작용을 할 때마다 updateErcDebt 함수가 호출된다. 이 함수는 ercDebtRate 가 증가했는지 확인하고 숏의 부채를 증가시키는 함수이다. 즉 변제 과정에서 불량채권의 부채를 전부 상환하지 못했다면 모든 숏의 부채를 증가시켜 이를 부담하게 하는 매커니즘이다.

function updateErcDebt(STypes.ShortRecord storage short, address asset) internal {
    AppStorage storage s = appStorage();
 
    // Distribute ercDebt
    uint64 ercDebtRate = s.asset[asset].ercDebtRate;
    uint88 ercDebt = short.ercDebt.mulU88(ercDebtRate - short.ercDebtRate);
 
    if (ercDebt > 0) {
        short.ercDebt += ercDebt;
        short.ercDebtRate = ercDebtRate;
    }
}

그런데 여기서 문제가 있다. updateErcDebt 함수는 부채 양을 증가시켜 담보율에 변화를 만들지만 updatedAt 는 업데이트 하지 않는다. 즉, updateErcDebt 를 통해 담보율이 떨어져 청산 대상이 되었지만 updatedAt는 최신화되지 않을 수 있다.

disputeRedemption 함수는 숏 청산 요청이 가능한 담보율을 가졌는데 청산 요청에 포함되지 않은 숏을 찾아 제시하면 청산 요청을 취소시키는 함수이다. 청산 요청이 생성된 지 한시간 이상 전에 업데이트 된 숏만 이의제기에 사용할 수 있다. 숏의 담보율을 updateErcDebt 를 통해 변동시킨 후 disputeRedemption 에 이용하면 정상적인 청산 요청도 취소시킬 수 있다.

updateErcDebt 함수는 internal 함수 이고 일반적으로 다른 함수와 함께 사용되어 updatedAt가 업데이트 되지만, proposeRedemption 를 통해 호출되었을 때는 따로 업데이트 하지 않는다. 따라서 proposeRedemption 를 통해 트리거할 수 있다.

Impact

공격자가 (원래는 취소 불가했던) 청산을 취소시키고 수수료를 얻거나, 자신의 숏이 청산되지 않도록 하거나, 청산을 방해하여 디페깅을 유발할 수 있다.

Mitigation

updateErcDebt 가 호출될 때마다 updatedAt를 업데이트한다.


tags: bughunting, dittoeth, smart contract, solidity, logic flaw, wrong state, severity medium