Appearance
S2C6: uint8 Overflow + Reentrancy
1. Problem
The contract has a points and level system, where mintFlag checks uint8(points << levels) == 32. It is necessary to find a combination of points and levels such that points << levels equals exactly 32 after uint8 overflow.
2. Cause
The contract uses uint8 casting to truncate the shift result. Since uint8 only has 8 bits (0-255), the left-shifted value wraps around if it exceeds 255. At the same time, the contract has a reentrancy vulnerability that allows unlimited points acquisition.
3. Solution
- Exploit the reentrancy vulnerability to obtain 59 points (59
claimPointscalls) - Upgrade 5 times (consuming 50 points, leaving 9 points, level 5)
- Verify:
uint8(9 << 5) = uint8(288) = 288 - 256 = 32 ✓ points(9) < 10 ✓andpoints × levels(45) >= 30 ✓
solidity
function solve() public {
counter = 0;
challenge.resetPoints();
challenge.claimPoints(); // reenters 58 more times → total 59
// 5 x upgradeLevel: points=9, levels=5
for (uint i = 0; i < 5; i++) challenge.upgradeLevel();
challenge.mintFlag(); // uint8(9<<5)=32 ✓
}
receive() external payable {
if (counter < 58) { counter++; challenge.claimPoints(); }
}
4. Pitfalls Encountered
Reentrancy Count and Overflow Parameter Matching: The number of reentrancy calls and upgrade operations must be precisely calculated so that the final parameters satisfy all checks. Incorrect initial calculations can lead to unsatisfied conditions.
5. Pitfall Causes
Three conditions constrain each other:
points < 10→ final points must be < 10points * levels >= 30→ points × level ≥ 30uint8(points << levels) == 32→ after shifting, uint8 truncation = 32
It is necessary to find a (points, levels) combination that satisfies all three conditions simultaneously, along with a path to reach that combination.
6. How to Resolve
Mathematical Analysis:
9 << 5 = 288,uint8(288) = 288 % 256 = 32points=9 < 10 ✓,9*5=45 >= 30 ✓- Path to reach: 59 claimPoints → points=59, 5 upgradeLevel → points=59-50=9
- Key: find the optimal combination where
points << levelsequals 32 under uint8
uint8 Shift Overflow Lookup Table:
| points | levels | p<<l | uint8(p<<l) |
|---|---|---|---|
| 9 | 5 | 288 | 32 ✓ |
| 1 | 5 | 32 | 32 ✓ |
| 2 | 4 | 32 | 32 ✓ |
Choose 9 and 5 because: points * levels = 45 >= 30 and points = 9 < 10.
7. Key Technical Points
| Point | Description |
|---|---|
| uint8 overflow | Left-shift results exceeding 255 are automatically truncated: uint8(x) == x % 256 |
| Reentrancy vulnerability | External call before state update → unlimited reentry |
| Parameter space search | Exhaustively enumerate points(1-255) × levels(0-255) to find combinations satisfying uint8(p<<l)==32 |
Core code: solutions/season2/Challenge6SolutionV2.sol (59 reentrancy calls + 5 upgrades)