Closed code423n4 closed 2 years ago
While there is an underflow possibility that we should check for (it wouldn't hurt), I can't see how this can result in losing funds. repayAmount
cannot be equal to 0 (see this line)
Invalid because CNft is compiled with ^0.8.0 and seizeAmounts = [type(uint256).max, 1]
would lead to overflow in totalAmount += amounts[i];
pragma solidity ^0.8.0;
uint256 totalAmount = 0;
for (uint256 i; i < length; ++i) {
if (!is1155) {
require(amounts[i] == 1, "CNFT: Amounts must be all 1s for non-ERC1155s.");
}
totalAmount += amounts[i];
Lines of code
https://github.com/bunkerfinance/bunker-protocol/blob/752126094691e7457d08fc62a6a5006df59bd2fe/contracts/CToken.sol#L1090-L1092
Vulnerability details
Issue: seizeAmounts[] > seizeTokens, seizeTokens will underflow because of solidity 5. Underflow allows an illegitimate amount of NFTs to be seized.
Consequence: If a user's borrow health drops to allow legitimate liquidation, an attacker can seize their ERC-1155 collateral for free.
Proof of Concept
liquidateBorrowNft
on a cToken CErc20.sol#L126seizeAmounts = [type(uint256).max, 1]
andsiezeIds = [1,2],
repayAmount` set to 0liquidateBorrowNftFresh
callscomptroller.liquidateBorrowAllowed
Comptroller.sol#L403liquidateBorrowAllowed
passes and the call chain goes back to the cTokencomptroller.liquidateCalculateSeizeNfts
is called, will returnsiezeTokens = 0
asrepayAmount = 0
seizeTokens -= seizeAmounts[i]
underflowsseizeTokens
from 0 to 1 CToken.sol#L1090-L1092seizeTokens
from 1 to 0.require(seizeTokens == 0)
check passescNft.seize
is calledrequire(seizeAmounts[i] == 1
check will fail_safeBatchTransferFrom
will succeed as it has no balance checksMitigations
Mitigation: Use safeMath for
seizeTokens -= seizeAmounts[i]