Skip to main content
A stack overflow (more precisely a stack-based buffer overflow) occurs when a program writes more data into a stack-allocated buffer than the buffer was sized to hold. The excess bytes spill into adjacent stack memory, potentially overwriting the saved base pointer (EBP/RBP) and the saved return address (EIP/RIP). Because control flow returns to whatever address is stored in the saved return address, an attacker who controls that value controls program execution.

How stack frames work

When a function is called, the CPU pushes the return address onto the stack, the callee saves the old frame pointer, and then allocates space for local variables. A typical 64-bit frame looks like this:
Functions such as gets, strcpy, strcat, and sprintf copy data without checking the destination size, making them classic vulnerability triggers.

Finding the offset to the return address

Using a De Bruijn (cyclic) pattern

Send a non-repeating pattern as input, observe which bytes end up in the instruction pointer after the crash, and calculate the offset.

Exploitation techniques

Ret2win

A ret2win challenge has a function inside the binary that is never called during normal execution — typically named win, secret, or similar. The exploit overwrites the return address with that function’s address.
ASLR is typically disabled in ret2win challenges because the binary is not PIE; the function address is fixed at link time.

Stack shellcode

If the stack is executable (NX absent) and ASLR is disabled, you can place shellcode in the buffer and redirect execution to it.

ROP (when NX is enabled)

When the stack is non-executable, use Return-Oriented Programming to chain existing code fragments. See the dedicated ROP page.

Windows SEH overflow

On 32-bit Windows, structured exception handler (SEH) records are stored on the stack. An overflow can overwrite the SEH chain:
  1. The nSEH field (4 bytes before the handler pointer) is set to a short jump (\xeb\x06\x90\x90) that skips over the handler pointer.
  2. The handler pointer is replaced with the address of a POP POP RET gadget.
  3. When the exception fires, POP POP RET redirects execution to nSEH, which jumps into the payload buffer.

Real-world examples

The /cgi-bin/api.values.get endpoint copies each colon-delimited token into a 64-byte stack buffer without length checks. A token longer than 64 bytes corrupts saved registers. NX is enabled but there is no canary or PIE, so a ROP chain built from fixed addresses achieves code execution.
An unbounded %s conversion in sscanf fills a 0x800-byte stack buffer from user-supplied URI data. Inputs longer than 0x800 bytes corrupt the stack canary and saved return address, causing a pre-authentication denial of service (and potentially RCE with an additional info leak).
alloca() is called with a size proportional to the number of HTTP chunked-transfer segments (16 bytes per segment). Sending hundreds of thousands of 6-byte chunks causes stack exhaustion without any bounds check, crashing the server.

Heap overflows

Overflows are not always on the stack. Heap-based overflows corrupt adjacent allocations and are covered in heap exploitation.

Protections quick reference