Weakness reference
CWE-121

Stack-based Buffer Overflow

A stack-based buffer overflow occurs when a program writes more data into a buffer than it can hold, and that buffer is stored on the stack. Because the stack…

01Summary

A stack-based buffer overflow occurs when a program writes more data into a buffer than it can hold, and that buffer is stored on the stack. Because the stack also holds critical data like function return addresses and local variables, an overflow can corrupt this data and allow an attacker to hijack program execution or crash the application. This is one of the oldest and most dangerous classes of memory corruption vulnerabilities.

02How It Happens

Stack-based buffer overflows typically arise when a program copies user-supplied input into a fixed-size buffer without validating the input length. Languages like C and C++ that do not perform automatic bounds checking are particularly vulnerable. When the input exceeds the buffer's capacity, the excess data overwrites adjacent stack memory. Because the stack grows downward (on most architectures) and stores return addresses and saved registers above local buffers, an attacker can craft input that overwrites a return address, causing the program to jump to attacker-controlled code when the function returns.

03Real-World Impact

Successful exploitation can lead to arbitrary code execution with the privileges of the vulnerable process. An attacker could gain shell access, steal sensitive data, install malware, or pivot to other systems on a network. Even if code execution is not achieved, the overflow may corrupt stack data in ways that cause denial of service or information disclosure. Stack-based overflows in network services, parsers, or system utilities are particularly critical because they can often be triggered remotely.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import ctypes

def process_user_input(user_data):
    # Simulating a fixed-size buffer (C-style)
    buffer = ctypes.create_string_buffer(16)
    # Unsafe copy: no length check
    ctypes.memmove(buffer, user_data.encode(), len(user_data))
    return buffer.value

# Attacker sends 50 bytes; overflow occurs
result = process_user_input("A" * 50)

Why it's vulnerable:
The code copies the entire user input into a 16-byte buffer without checking the input length. If user_data is longer than 16 bytes, it overwrites adjacent stack memory.

Fixed pattern
import ctypes

def process_user_input(user_data, max_length=16):
    # Validate input length before copying
    if len(user_data) > max_length:
        raise ValueError(f"Input exceeds maximum length of {max_length}")
    buffer = ctypes.create_string_buffer(max_length)
    ctypes.memmove(buffer, user_data.encode(), len(user_data))
    return buffer.value
Vulnerable pattern
<?php
function process_user_input($user_data) {
    // Simulating a fixed buffer (C-style vulnerability pattern)
    // In real PHP, this would typically occur in C extensions or via FFI
    $buffer = str_pad("", 16, "\x00");
    // Unsafe operation: no bounds check
    $buffer = substr_replace($buffer, $user_data, 0, strlen($user_data));
    return $buffer;
}

// Attacker sends 50 bytes
$result = process_user_input(str_repeat("A", 50));
?>

Why it's vulnerable:
The code does not validate the length of $user_data before writing it into a fixed-size buffer. Excess data overwrites adjacent memory.

Fixed pattern
<?php
function process_user_input($user_data, $max_length = 16) {
    // Validate input length
    if (strlen($user_data) > $max_length) {
        throw new Exception("Input exceeds maximum length of {$max_length}");
    }
    $buffer = str_pad("", $max_length, "\x00");
    $buffer = substr_replace($buffer, $user_data, 0, strlen($user_data));
    return $buffer;
}
?>

05Prevention Checklist

Use safe string functions:
Replace strcpy(), strcat(), and sprintf() with length-bounded alternatives like strncpy(), strncat(), and snprintf().
Validate input length:
Always check the size of user-supplied input before copying it into a buffer; reject or truncate oversized input.
Use modern languages:
Prefer languages with automatic memory management (Python, Java, C#) or safe abstractions (Rust) for new code.
Enable compiler protections:
Use stack canaries, address space layout randomization (ASLR), and data execution prevention (DEP/NX) to mitigate exploitation.
Perform code review:
Scrutinize all manual memory operations, especially in C/C++ code that handles external input.
Test with fuzzing:
Use fuzzing tools to send malformed and oversized input to identify buffer overflow conditions.

06Signs You May Already Be Affected

Unexpected crashes or segmentation faults in applications, especially when processing unusual or large input, may indicate a buffer overflow. Unusual behavior such as program hangs, memory corruption errors in logs, or unexplained privilege escalation could also suggest exploitation. If you maintain C/C++ code that processes untrusted input, review it for unbounded string operations and fixed-size buffers.

07Related Recent Vulnerabilities