Buffer Overflow

Writing past the end of a fixed-size buffer corrupts adjacent memory, often hijacking control flow.

Definition

A buffer overflow occurs when a program writes more data into a fixed-size memory buffer than the buffer can hold. The excess bytes overwrite adjacent memory: a return address on the stack, a function pointer, a heap-allocator metadata field. Depending on what gets overwritten and how predictable the layout is, the consequences range from a crash to arbitrary code execution.

Buffer overflow is the bug class that defined memory-corruption security research from the 1990s through the early 2000s. The classic stack-smashing attack — overwrite the return address, redirect execution into a shellcode buffer — is now reliably blocked by stack canaries, ASLR, DEP/NX, and CFI. But variants persist: heap overflows, off-by-one errors, integer-overflow-into-allocator, and CWE-787 (out-of-bounds write) appear in MITRE's top-25 every year.

How it works

The classic pattern: a fixed-size buffer on the stack, a `strcpy` (or `gets`, or `sprintf` with an unbounded format) that copies attacker-controlled input into it without checking length. Excess bytes overflow into the saved frame pointer and return address. When the function returns, control transfers to an address of the attacker's choosing.

Modern exploitation is harder. ASLR randomises the base addresses of libraries and the stack, so the attacker cannot hard-code an absolute jump target. DEP/NX marks the stack non-executable, so shellcode there cannot run. Stack canaries detect overflow before the return address is consumed. The contemporary technique is ROP — chaining short snippets of existing code that already live in the program — and one of the goals of CFI (Control Flow Integrity) is to block ROP as well.

Impact

Crashes (DoS), information disclosure (when the overflow reaches a read-out path), and, when the chain is complete, arbitrary code execution.

Mitigation

Use memory-safe languages where possible (Rust, Go, Java, Python, .NET). When you must use C/C++, prefer bounded APIs (`strncpy` with explicit termination, `snprintf`, `std::string`, `std::array` with `.at()`). Enable every compiler hardening flag: `-D_FORTIFY_SOURCE=2`, `-fstack-protector-strong`, `-fPIE -pie`, `-Wl,-z,relro,-z,now`, CFI. Run fuzzers (AFL++, libFuzzer) against every parser. The OS-level mitigations (ASLR, DEP, hardened malloc) are non-negotiable today.

Examples

  • CVE-2014-0160 — Heartbleed; OpenSSL out-of-bounds read.
  • CVE-2019-0708 — BlueKeep; pre-auth RDP heap overflow.

See also

References