Acidic Eggshell Parrot
High
https://github.com/sherlock-audit/2024-12-mach-finance/blob/main/contracts/src/CToken.sol#L422
https://github.com/sherlock-audit/2024-12-mach-finance/blob/main/contracts/src/CToken.sol#L429
The root cause of the vulnerability is the potential for integer overflow in the mintInternal function when passing a large value close to 2^256 - 100. This will cause unexpected behavior for users as an attacker could manipulate the minting process, leading to excessive token minting and potentially financial losses or contract failure.
In CTToken.sol:529
, the calculation and storage updates for minting tokens can lead to an overflow vulnerability when the mintAmount is close to 2^256 - 100, causing unexpected behavior.
Unexpected Minting of Huge Amounts:
A malicious user could supply a seemingly "negative" value (e.g., -100), which would be interpreted as a very large unsigned integer (2^256 − 100). This could result in minting an excessive number of cTokens, leading to a massive inflation of totalSupply and an unfair balance for the attacker.
Internal Pre-conditions for the vulnerability to manifest:
Minter needs to call mintInternal() to supply an amount (mintAmount) to the contract that could lead to a calculation where the mint amount exceeds the contract's capacity to handle it, such as values close to 2^256 - 100.
Contract state needs to have no overflow check for the minting process, allowing the calculation of new values such as totalSupply and accountTokens[minter] to overflow when excessively large mintAmount is provided.
comptroller.mintAllowed() function needs to allow minting and not reject the operation, which would otherwise prevent this overflow vulnerability from occurring.
accrualBlockTimestamp needs to match the current block timestamp when mintInternal() is called.
Underlying token contract needs to allow minting
External interest rate model needs to function correctly
External market conditions may affect minting amounts
External oracle or data feed dependencies
Attacker interacts with the mintInternal function: The attacker calls the mintInternal function, providing a mintAmount that is close to the overflow threshold (e.g., 2^256 - 100).
Interest is accrued
Minting process begins
Mint amount is transferred: The attacker successfully transfers the mintAmount (e.g., 2^256 - 100) into the contract via the doTransferIn function.
Exchange rate is calculated
Overflow occurs when calculating cTokens
Total supply and account balances are updated
Event emission
Potential exploit consequences
The protocol suffers an approximate loss of tokens due to the overflow vulnerability, as the minting process can result in an excessive number of cTokens being minted.
The attacker gains a disproportionate amount of cTokens, potentially draining the protocol's assets or destabilizing the token supply by exploiting the overflow during the minting process.
Here is a simple Proof of Concept (PoC) demonstrating the vulnerability that occurs when a negative value, such as -100, is passed into the mintInternal() function and results in an overflow:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface CToken {
function mintInternal(uint256 mintAmount) external;
}
contract VulnerabilityPoC {
CToken cToken;
constructor(address _cTokenAddress) {
cToken = CToken(_cTokenAddress);
}
// Attack function
function attack() external {
// Trying to mint an invalid mintAmount (-100)
uint256 mintAmount = uint256(int256(-100)); // Cast -100 to uint256, which causes an overflow
// Call the vulnerable mintInternal function
cToken.mintInternal(mintAmount);
}
}
If there are no checks in place, this will cause the contract to mint an excessive amount of cTokens, potentially destabilizing the protocol.
-
Input Validation (Pre-checks) Add explicit checks to ensure that mintAmount is a valid positive value before it is used in the contract. This will prevent any overflows and invalid values from being processed. solidity Copy code function mintInternal(uint256 mintAmount) internal nonReentrant { // Add validation to ensure mintAmount is positive require(mintAmount > 0, "Invalid mint amount");
accrueInterest(); mintFresh(msg.sender, mintAmount); } Explanation: The require(mintAmount > 0) statement ensures that the minting process cannot be initiated with zero or negative values. If the input fails this check, the transaction will revert.
-
Use a Safe Math Library