Use Solmate, and implement upper bounds for time differences and schnibble generation. And using a more precise calculation method that avoids potential for overflows.
Here's one fix, an opinionated one:
import {SafeCastLib} from "solmate/utils/SafeCastLib.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {ReentrancyGuard} from "solmate/utils/ReentrancyGuard.sol";
contract LandManager is BaseBlastManagerUpgradeable, ILandManager, ReentrancyGuard {
using SafeCastLib for uint256;
using FixedPointMathLib for uint256;
uint256 constant MAX_TIME_DIFFERENCE = 30 days;
uint256 constant MAX_SCHNIBBLES_PER_SECOND = 1e6;
uint256 constant MAX_BONUS_PERCENTAGE = 200; // Maximum 200% bonus
function _farmPlots(address _sender) internal nonReentrant {
// current is same
for (uint8 i = 0; i < staked.length; i++) {
// current is same
uint256 timeDiff = (block.timestamp - _toiler.lastToilDate).min(MAX_TIME_DIFFERENCE);
uint256 baseSchnibbles = timeDiff * BASE_SCHNIBBLE_RATE;
require(baseSchnibbles <= timeDiff * MAX_SCHNIBBLES_PER_SECOND, "Excessive schnibble generation");
int256 cappedBonus = finalBonus.toInt256().clamp(-100, MAX_BONUS_PERCENTAGE.toInt256());
uint256 bonusSchnibbles = baseSchnibbles.mulWadUp(uint256(cappedBonus + 100));
schnibblesTotal = bonusSchnibbles;
// Add this additional safety check
require(schnibblesTotal <= type(uint128).max, "Schnibble overflow");
// current is same
}
}
}
This mitigation does the following:
Uses SafeCastLib for safe conversions between uint256, int256.
Uses FixedPointMathLib for more precise calculations (mulWadUp for percentage calculations).
Add additional ReentrancyGuard protection, to prevent potential reentrancy.
Uses the .min() function from FixedPointMathLib to cap the time difference.
Uses .clamp() to ensure the bonus stays within the desired range.
Lines of code
https://github.com/code-423n4/2024-07-munchables/blob/main/src/managers/LandManager.sol#L232
Vulnerability details
What and where is the bug
The bug is in the _farmPlots() function, in the
schnibbles
calculation, differing to the edgecase mentioned:Vulnerability vector
This calculation is vulnerable to integer overflow, which could be exploited to generate an excessive amount of
schnibbles
. The issue arises from:schnibblesTotal
could overflow if(timestamp - _toiler.lastToilDate)
is large or ifBASE_SCHNIBBLE_RATE
is set to a high value.finalBonus
could also overflow, especially iffinalBonus
is a significant large positive number.int256
and back touint256
could lead to negative patterns with very large numbers.Impact
A black hat could exploit the vulnerability to:
schnibbles
, far far beyond what should be possible given the constraints intended.schnibble
distribution.Proof of Concept
Add this named
snibble.test.ts
to here and it will pass, showing the bug exists.Prove of test passing:
✅
Recommended Fix
To mitigate:
Here's one fix, an opinionated one:
This mitigation does the following:
uint256
,int256
..min()
function from FixedPointMathLib to cap the time difference..clamp()
to ensure the bonus stays within the desired range.Assessed type
Context