Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')

Description

Classic Buffer Overflow is a vulnerability that occurs when a program copies data to a buffer without first checking that the data fits within the buffer's allocated size. This typically happens when functions like strcpy(), gets(), sprintf(), or memcpy() are used without proper bounds checking. When the input data exceeds the buffer capacity, it overwrites adjacent memory locations, potentially corrupting data, crashing the program, or enabling arbitrary code execution. This vulnerability class has been responsible for numerous high-profile security breaches and remains a critical concern in C/C++ applications despite decades of awareness.

Risk

Buffer overflows are among the most dangerous vulnerabilities in software security. Attackers can exploit them to overwrite function return addresses, redirecting program execution to injected shellcode. Stack-based overflows enable reliable code execution through return-oriented programming (ROP) and other techniques that bypass modern protections like DEP/NX. Heap overflows can corrupt memory management structures for similar effect. Even with exploit mitigations, buffer overflows frequently cause denial of service through crashes. Critical systems written in C/C++ including operating systems, network services, and embedded devices remain at risk. The Morris Worm (1988), Code Red (2001), and Heartbleed (2014) all exploited buffer-related vulnerabilities.

Solution

Use safe string handling functions with explicit bounds checking: strncpy(), snprintf(), strlcpy(), or platform-specific safe alternatives like strcpy_s(). Better yet, use languages with automatic bounds checking (Rust, Go, Java) or C++ containers (std::string, std::vector) that manage memory safely. Enable compiler protections: stack canaries (-fstack-protector), ASLR, DEP/NX, and Control Flow Integrity (CFI). Use static analysis tools (Coverity, PVS-Studio) and dynamic analysis (AddressSanitizer, Valgrind) to detect buffer overflows during development. Validate all input sizes before copying. Consider using memory-safe wrappers or libraries.

Common Consequences

ImpactDetails
AvailabilityScope: Availability

Buffer overflows commonly cause crashes and denial of service when corrupted memory leads to invalid memory access or corrupted control flow.
IntegrityScope: Integrity

Attackers can modify program data, corrupt memory structures, or alter program execution flow through carefully crafted overflow inputs.
ConfidentialityScope: Confidentiality

Memory corruption can expose sensitive data in adjacent memory locations or enable information disclosure through controlled overreads.
Access ControlScope: Code Execution

Successful exploitation enables arbitrary code execution with the privileges of the vulnerable process, potentially leading to complete system compromise.

Example Code + Solution Code

Vulnerable Code

#include <stdio.h>
#include <string.h>

// VULNERABLE: strcpy without bounds checking
void vulnerable_login(char *username) {
    char buffer[64];
    // Attack: Username > 64 bytes overwrites stack
    strcpy(buffer, username);  // No bounds check!
    printf("Welcome, %s\n", buffer);
}

// VULNERABLE: gets() is always unsafe
void get_input() {
    char input[100];
    gets(input);  // Never use gets()! No bounds checking.
}

// VULNERABLE: sprintf without size limit
void format_message(char *user_data) {
    char buffer[256];
    sprintf(buffer, "User said: %s", user_data);  // Overflow if user_data > ~244 chars
}

Fixed Code

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// SAFE: Using strncpy with explicit size
void safe_login(const char *username) {
    char buffer[64];
    strncpy(buffer, username, sizeof(buffer) - 1);
    buffer[sizeof(buffer) - 1] = '\0';  // Ensure null termination
    printf("Welcome, %s\n", buffer);
}

// SAFE: Using fgets instead of gets
void safe_get_input() {
    char input[100];
    if (fgets(input, sizeof(input), stdin) != NULL) {
        // Remove trailing newline if present
        input[strcspn(input, "\n")] = '\0';
    }
}

// SAFE: Using snprintf with size limit
void safe_format_message(const char *user_data) {
    char buffer[256];
    snprintf(buffer, sizeof(buffer), "User said: %s", user_data);
    // snprintf automatically truncates and null-terminates
}

// BEST: Using dynamic allocation with size validation
char* safe_copy(const char *input, size_t max_len) {
    size_t len = strnlen(input, max_len);
    char *buffer = malloc(len + 1);
    if (buffer == NULL) {
        return NULL;
    }
    memcpy(buffer, input, len);
    buffer[len] = '\0';
    return buffer;
}

// Compile with: gcc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2

Exploited in the Wild

Morris Worm (Internet, 1988)

The Morris Worm exploited a buffer overflow in the Unix fingerd service's gets() function, becoming one of the first major internet worms. It infected approximately 6,000 computers (10% of the internet at the time), causing widespread disruption and leading to the creation of CERT.

Code Red Worm (Microsoft IIS, 2001)

Code Red exploited a buffer overflow in Microsoft IIS web server's ISAPI extension handling, infecting over 350,000 servers within 14 hours. The worm defaced websites and launched DDoS attacks against the White House, causing an estimated $2.6 billion in damages.

Heartbleed (OpenSSL, 2014)

While technically a buffer over-read (CWE-125), Heartbleed in OpenSSL demonstrated buffer vulnerability impact at massive scale. The flaw exposed up to 64KB of server memory per request, leaking private keys, session cookies, and passwords from millions of servers worldwide.


Tools to test/exploit

  • AddressSanitizer (ASan) — runtime memory error detector that catches buffer overflows, use-after-free, and other memory bugs.

  • Valgrind — memory debugging and profiling tool that detects buffer overflows and memory leaks.

  • American Fuzzy Lop (AFL++) — coverage-guided fuzzer effective at discovering buffer overflow vulnerabilities.

  • pwntools — CTF framework and exploit development library for crafting buffer overflow exploits.


CVE Examples

  • CVE-2021-44228 — While a code injection, related to unsafe input handling in logging.

  • CVE-2014-0160 — Heartbleed OpenSSL buffer over-read exposing server memory.

  • CVE-2019-14287 — sudo buffer handling flaw enabling privilege escalation.


References

  1. MITRE. "CWE-120: Buffer Copy without Checking Size of Input." https://cwe.mitre.org/data/definitions/120.html

  2. OWASP. "Buffer Overflow Attack." https://owasp.org/www-community/attacks/Buffer_overflow_attack

  3. CERT. "Secure Coding in C and C++." https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard