sherlock-audit / 2024-06-makerdao-endgame-judging

1 stars 1 forks source link

zhoo - Attackers can prevent liquidation #91

Closed sherlock-admin2 closed 1 month ago

sherlock-admin2 commented 1 month ago

zhoo

Medium

Attackers can prevent liquidation

Summary

locker by calling LockstakeEngine.lock causes onKick -> VoteDelegate.free to fail. This leads to the failure of liquidation.

Root Cause

onKick -> _selectVoteDelegate -> VoteDelegateLike(prevVoteDelegate).free(wad) -> chief.free(wad) -> require(block.number > last[msg.sender])

onKick will eventually call chief.free. If chief.lock is called, the call to chief.free will fail in the same block, so onKick will fail.

If onKick cannot be called, the liquidation fails.

https://etherscan.io/address/0x0a3f6849f78076aefadf113f5bed87720274ddc0#code

    function lock(uint wad) public note{
@>   last[msg.sender] = block.number;
        GOV.pull(msg.sender, wad);
        IOU.mint(msg.sender, wad);
        deposits[msg.sender] = add(deposits[msg.sender], wad);
        addWeight(wad, votes[msg.sender]);
    }

reserveHatch prevents VoteDelegate.lock from being called multiple times, but the attacker can still call it in a certain time interval.

When block.number > hatchTrigger + HATCH_SIZE and block.number < hatchTrigger + HATCH_SIZE + HATCH_COOLDOWN

If liquidation occurs at this point, the user can avoid liquidation by calling the lock function.

The liquidation was not carried out in time, and if the price continued to fall it would result in the loss of user funds.

LockstakeEngine.lock can be called by anything, and an attacker can call this function by locking a small number of tokens.

https://github.com/sherlock-audit/2024-06-makerdao-endgame/blob/dba30d7a676c20dfed3bda8c52fd6702e2e85bb1/vote-delegate/src/VoteDelegate.sol#L98

https://github.com/sherlock-audit/2024-06-makerdao-endgame/blob/dba30d7a676c20dfed3bda8c52fd6702e2e85bb1/lockstake/src/LockstakeEngine.sol#L426

Internal pre-conditions

  1. The user needs to be liquidated

External pre-conditions

  1. block.number > hatchTrigger + HATCH_SIZE and block.number < hatchTrigger + HATCH_SIZE + HATCH_COOLDOWN

Attack Path

The attackers found out that someone was going to be liquidated. The attacker uses front-runnig to invoke LockstakeEngine.lock before onKick is invoked. The onKick call fails and the attacker prevents himself from being liquidated. The attack may fail depending on the value of the hatchTrigger, but it can also be successful in 1 block or 20 blocks(HATCH_COOLDOWN = 20).

Impact

Causes a liquidation failure within the time limit allowed by hatchTrigger. Failure to settle in a timely manner may result in a loss of the funds (asset prices continue to fall)

PoC

No response

Mitigation

Allow the clearing module to call chieft.free without relying on hatchTrigger checks.

Duplicate of #62

telome commented 1 month ago

reserveHatch secures a window in which liquidation is possible. Its cooldown period of 20 blocks is chosen carefully so its impact on kicking liquidations is reasonable (especially given that Maker oracles are already delayed).