Independent perspectives on Indonesia

What Is a Buffer Overflow? How It Works and How to Prevent It

Ever wonder how a single line of sloppy code can hand over full control of a server to an attacker? That's the story behind one of the oldest and most persistent vulnerability classes in software security: the buffer overflow. It's been around since the 1980s, it's still showing up in CVE databases today, and understanding it is practically a rite of passage for anyone getting into systems programming or security.

This guide breaks down what a buffer overflow actually is, walks through real vulnerable code so you can see the bug with your own eyes, and covers the modern defenses that make exploiting one far harder than it used to be.

Cr Image: ChatGPT.

What Is a Buffer Overflow?

A buffer overflow happens when a program writes more data into a fixed-size block of memory (a buffer) than it was allocated to hold. The extra data spills over into adjacent memory, corrupting whatever was stored there: other variables, pointers, or, in the worst case, the address the program is supposed to jump back to when a function finishes running.

At its core, this is a bounds-checking failure. The programming language (usually C or C++) doesn't automatically stop you from writing past the end of an array. It's entirely on the developer to make sure input never exceeds the space reserved for it. Miss that check once, and you've got a vulnerability.

A Quick Tour of Process Memory

To understand why an overflow is dangerous, it helps to know roughly how a running program's memory is laid out. A typical process memory space includes:

  • The stack: stores function arguments, local variables, and the return address the CPU jumps to once a function finishes. It grows downward as functions call other functions.
  • The heap: holds dynamically allocated memory, the kind you get from something like malloc().
  • .data and .bss: hold global and static variables (initialized and uninitialized, respectively).
  • .text: holds the actual compiled instructions of the program.

The stack is where the classic buffer overflow does its damage. Every time a function is called, a "stack frame" is set up containing its local variables and, critically, the return address, the location in memory the CPU should jump back to once that function is done executing. If a local buffer sits below that return address in memory and gets overflowed, the extra bytes can overwrite the return address itself.

A Real Vulnerable Code Example

Here's a small, self-contained example of the exact kind of bug that causes stack-based buffer overflows:

#include <stdio.h> #include <string.h> int main(int argc, char **argv) { char small_buffer[8]; strcpy(small_buffer, argv[1]); printf("You entered: %s\n", small_buffer); return 0; }

small_buffer is only 8 bytes. But strcpy() doesn't care how big the destination buffer is, it just keeps copying bytes from the source until it hits a null terminator. If you run this program with an input longer than 8 characters, the extra bytes get written past the end of the buffer, into whatever memory comes next on the stack. Run it with a long enough string, and you'll eventually overwrite the saved return address, at which point the program will typically crash with a segmentation fault because it tries to jump to an invalid address when the function returns.

That crash is actually the "safe" outcome. If an attacker can carefully control exactly what bytes end up in that overwritten memory (instead of random garbage causing a crash), they can redirect execution to code of their choosing. That's the difference between a bug and an exploit, and it's exactly why we're not walking through how to build that part.

Why This Keeps Showing Up: A Bit of History

Buffer overflows aren't a theoretical concern. They've caused some of the most significant security incidents in computing history:

  • The Morris Worm (1988): widely considered the first major buffer overflow exploit in the wild. It abused a stack overflow in the Unix fingerd daemon and ended up infecting roughly 10% of the internet within two days, an event that directly led to the creation of the first Computer Emergency Response Team (CERT).
  • Code Red (2001) and SQL Slammer (2003): both worms spread using buffer overflow vulnerabilities in Microsoft server software, infecting hundreds of thousands of machines within hours.
  • Heartbleed (2014): a buffer over-read (a close cousin of the overflow) in OpenSSL's Heartbeat extension let attackers read sensitive memory, including private keys and passwords, from millions of servers worldwide.

Each of these traces back to the same root cause: a program trusting input length instead of verifying it.

How Modern Systems Defend Against Buffer Overflows

The reason buffer overflows are much harder to exploit successfully today than they were in the 1990s and 2000s comes down to several overlapping defenses baked into modern compilers and operating systems:

Stack Canaries

A stack canary is a random value placed right before the return address on the stack. Before a function returns, the program checks whether that value has changed. If it has, something has overflowed the buffer and corrupted memory, and the program terminates immediately instead of continuing to execute. Modern compilers like GCC enable this automatically with flags like -fstack-protector-strong.

NX Bit / DEP (Data Execution Prevention)

This marks memory regions like the stack and heap as non-executable. Even if an attacker manages to inject malicious code into memory, the CPU refuses to execute it from a region that's flagged as data-only.

ASLR (Address Space Layout Randomization)

ASLR randomizes where key parts of a program, like the stack, heap, and shared libraries, are loaded in memory each time it runs. This makes it much harder for an attacker to predict the exact memory address they'd need to target.

Bounds-Checked Functions and Safer Coding Practices

Modern C codebases are steadily moving away from unsafe functions like strcpy(), gets(), and sprintf() in favor of bounded alternatives like strncpy(), fgets(), and snprintf(), which take a maximum length and won't write past it. Static analysis tools and compiler warnings (-Wall -Wextra, _FORTIFY_SOURCE) also catch a lot of these bugs before code ever ships.

None of these defenses is bulletproof on its own, security researchers regularly publish techniques for bypassing individual protections, but layered together, they make successful exploitation dramatically harder than it was in the era when Aleph One's Smashing the Stack for Fun and Profit first popularized the technique.

Final Thoughts

Buffer overflows are a great example of how a tiny, easy-to-miss mistake (trusting input length without checking it) can cascade into full system compromise. The good news is that between safer language choices, compiler protections, and OS-level defenses, the attack surface for classic overflow exploits has shrunk enormously since the days of the Morris Worm. The bad news is that the underlying mistake, unchecked memory writes, is still something developers make today, which is exactly why buffer overflow still shows up on vulnerability disclosure lists every year.

If you want to go deeper on the exploitation side in a legal, hands-on environment, platforms like TryHackMe, HackTheBox, and PortSwigger's Web Security Academy are built specifically for practicing this safely against systems designed for it.

Post a Comment for "What Is a Buffer Overflow? How It Works and How to Prevent It"

Read beyond the headlines.

Get new ideas, explainers and perspectives from BIN ENJAH in your reader.