two-sum picoCTF 2023 Solution

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 and submit two large positive values that overflow when added.

bash
wget https://artifacts.picoctf.net/c/456/flag.c
bash
printf '2147483647\n2147483647\n' | nc saturn.picoctf.net 60781
  1. Step 1Confirm the int width with objdump
    Disassemble the binary and grep for the comparison; a signed 32-bit int check appears as cmp against 0x7fffffff (INT_MAX). That confirms the wrap-around at exactly 2^31 - 1.
    bash
    objdump -d ./flag | grep -E 'cmp.*0x7fffffff' -B2 -A2
    Learn more

    Integer overflow occurs when an arithmetic operation produces a result outside the range representable by the integer type. A 32-bit signed integer holds 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 does not 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. The disassembly check anchors that intuition; if you see cmp eax, 0x7fffffff in the comparison's neighborhood, you are looking at a signed 32-bit int and the wrap point is exactly where you expect it.

  2. Step 2Submit the overflow pair
    Pipe two INT_MAX values into the service. The sum wraps to a negative number, the bogus inequality holds, and the flag prints.
    bash
    printf '2147483647\n2147483647\n' | nc saturn.picoctf.net 60781
    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 INT_MAX 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:

    • CVE-2018-10933 (libssh): integer-handling bug let attackers bypass authentication entirely.
    • CVE-2022-37454 (XKCP/SHA-3): integer overflow in the official Keccak/SHA-3 implementation triggered a buffer overflow exploitable in any consumer of the library.
    • The Ariane 5 rocket crash (1996): a 64-bit float was cast to a 16-bit integer, overflowing and shutting down the guidance system. Old, but still the canonical example of why width conversions matter.
    • Game economy 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. For more on the disassembly workflow used here, see Buffer Overflow Binary Exploitation in CTF.

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