Integer Overflow and Integer Bugs
Integers in C have a fixed size (32 or 64 bits) and a limited range. When an operation produces a value outside that range, it “wraps around” (overflow/underflow), and if a signed number is treated as unsigned (or vice versa), its value changes drastically (signedness). These bugs are dangerous because those integers are often used as buffer sizes or indices: a wrong calculation leads to allocating too little memory, reading/writing out of bounds, or skipping a check — and from there to a classic overflow.
Bug types
Section titled “Bug types”Integer overflow x + y exceeds the max -> wraps to a small/negative value # in 32 bits: 0xFFFFFFFF + 1 = 0 (wraps to 0)Integer underflow 0 - 1 in unsigned -> 0xFFFFFFFF (huge)Signedness a negative int treated as unsigned -> giant number # -1 (int) interpreted as unsigned = 4294967295Truncation assigning an int (32) to a short (16) -> high bits lostMultiplication len * sizeof(x) overflows -> allocates less than expectedWhy they’re exploitable
Section titled “Why they’re exploitable”The danger isn’t the integer itself but what it’s used for:
# 1) controlled allocation size -> heap/stack overflowint n = user_input; // attacker enters a value that overflowschar *buf = malloc(n * 8); // n*8 overflows -> malloc allocates little// then n elements are written -> heap overflow
# 2) skip a bounds checkif (index < MAX) { array[index] = x; } // if index is negative (signed) it passes the check// but array[index] writes OUTSIDE the array (negative index)
# 3) underflow in a size -> huge copysize_t len = header_len - 20; // if header_len < 20, len = huge -> memcpy overflowThe key pattern: an attacker-controlled integer feeding a malloc, a memcpy, an array index, or an if (x < limit) check.
How to find them
Section titled “How to find them”# in reversing/code: look for arithmetic on sizes/indices# before malloc, memcpy, read, loops# bounds checks using signed where it should be unsigned# fuzz with extreme values: 0, -1, 0xFFFFFFFF, INT_MAX, INT_MIN, large sizesFrom integer bug to exploitation
Section titled “From integer bug to exploitation”1. Find the controlled integer feeding a size/index/check2. Choose a value that causes the desired effect: - overflow -> small allocation -> heap/stack overflow (see pwn-stack/pwn-heap) - signedness/negative -> skip the limit -> out-of-bounds write - underflow -> giant size -> massive copy3. Turn the resulting memory corruption into flow control (like a classic overflow)The integer bug is often the first link that enables a classic stack or heap overflow.
For the defense
Section titled “For the defense”- Correct range checks: validate before operating; use unsigned types for sizes (
size_t) and verify upper and lower bounds. - Overflow detection: safe functions (
__builtin_add_overflow, C23’sckd_add),-ftrapv, UBSan (UndefinedBehaviorSanitizer) in development. - Don’t compute sizes with arithmetic without checking overflow (
if (n > MAX/8) error;beforen*8). - Fuzzing with boundary values; code review focused on size arithmetic.
Testing checklist
Section titled “Testing checklist”- Identify controlled integers feeding sizes/indices/checks
- Test boundary values (0, -1, 0xFFFFFFFF, INT_MAX/MIN)
- Overflow in a size calculation → small allocation → overflow
- Signedness/negative → skip a bounds check
- Underflow → giant size → massive copy
- Chain with stack/heap overflow (Stack Buffer Overflow/Heap Exploitation)
- Turn into flow control
- Blue: range validation, size_t, UBSan?