two-sum

Published: April 26, 2023

Description

The bank's challenge asks for two positive integers that satisfy n1 > n1 + n2 or n2 > n1 + n2. Triggering 32-bit integer overflow is the intended exploit.

Review the provided source to confirm the comparison uses signed 32-bit ints.

Connect to the service via nc saturn.picoctf.net 60781 and submit two large positive values that overflow when added.

wget https://artifacts.picoctf.net/c/456/flag.c && cat flag.c
python3 - <<'PY'
print(2147483647)
print(2147483647)
PY | nc saturn.picoctf.net 60781

Solution

  1. Step 1Understand the constraint
    Because 32-bit signed addition wraps, adding two maximum ints produces a negative result. This satisfies the inequality check.
    Learn more

    Integer overflowoccurs when an arithmetic operation produces a result outside the range representable by the integer type. A 32-bit signed integer can hold values from -2,147,483,648 to 2,147,483,647 (INT_MIN to INT_MAX). When you add 2,147,483,647 + 2,147,483,647, the mathematical result (4,294,967,294) exceeds INT_MAX, so it wraps around to -2 in two's complement arithmetic.

    Two's complement is the near-universal representation of signed integers in hardware. In two's complement, addition and subtraction work identically for signed and unsigned numbers at the bit level - the CPU doesn't distinguish. Overflow just means the carry bit is discarded, and the result is interpreted as a signed value. For 32 bits: 0x7FFFFFFF + 0x7FFFFFFF = 0xFFFFFFFE = -2 when read as signed.

    The condition n1 > n1 + n2 is logically impossible for positive integers in math. But in C with 32-bit signed ints, if the sum wraps to a negative number, a positive n1 is indeed greater than the negative sum. This is the bug the challenge exploits.

  2. Step 2Submit the overflow pair
    Send 2147483647 twice (or any pair that sums beyond INT_MAX). The service interprets the overflow and prints the flag.
    Learn more

    INT_MAX (2,147,483,647 = 2^31 - 1) is the maximum value for a 32-bit signed integer. Any pair of positive integers whose sum exceeds 2,147,483,647 will overflow and produce a negative (or unexpectedly small) result. Using INT_MAX twice is the cleanest choice because it maximally overflows, but values like 1,200,000,000 + 1,000,000,000 would also work.

    Real-world impact of integer overflow is serious and well-documented. Notable examples include:

    • The Ariane 5 rocket crash (1996) - a 64-bit float was cast to a 16-bit integer, overflowing and causing the guidance system to shut down
    • Android's libpng vulnerability (2015) - integer overflow led to a heap buffer overflow exploitable via malicious PNG files
    • Many game exploits - item counts and gold values stored as 32-bit ints that wrap around when maximized

    In C, signed integer overflow is formally undefined behavior - the compiler is allowed to assume it never happens and optimize accordingly, which can introduce security vulnerabilities even when the developer expects wrap-around behavior. Unsigned integers, by contrast, are defined to wrap. Languages like Rust and Swift trap on overflow by default in debug builds.

Flag

picoCTF{Tw0_Sum_Integer_Bu773R_0v3rf...8bd}

Any pair causing signed overflow works; using INT_MAX keeps the math simple.

Want more picoCTF 2023 writeups?

Useful tools for Binary Exploitation

Related reading

What to try next