The copy has no idea how big the destination is.
Consider strcpy(destination, source). It copies bytes through the source’s first zero byte, including that terminator. It does not receive the destination capacity. If the destination is too small, a valid source string can still trigger an out-of-bounds write.
/* Vulnerable pattern. Read it; do not treat it as a safe helper. */
void copy_name(const char *source) {
char name[16];
strcpy(name, source); /* destination capacity is not checked */
}The source must itself be valid and terminated. In the paper, one example fills a source array without explicitly adding its final zero. That can introduce an out-of-bounds read before you even reason about the destination. Our model always supplies a terminator and counts it explicitly.
Predict the first illegal byte.
This optional overflow model becomes interactive with JavaScript. The lesson, explanations and checkpoint answer remain readable without it.
A distance is not a guarantee of exploitation.
This chosen frame has a sixteen-byte buffer, four bytes of saved frame pointer and four bytes of saved return address. Therefore the first return-address byte is twenty bytes from the buffer start. With sixteen nonzero source characters, the terminator is already outside the buffer. With twenty, that terminator reaches the return address.
Those are offsets in our simulator. The paper’s five-byte-buffer example has different padding assumptions; a modern binary can differ completely. Undefined behavior also means a real compiler is not required to preserve this adjacent layout.
A useful evidence ladder is: an out-of-bounds write exists; particular adjacent bytes change; saved control data changes; the changed control data is used; a specific outcome is verified. Do not jump from “segfault” to “arbitrary code execution.” Corruption of ordinary data can also be dangerous without overwriting RET.
Little-endian is a storage order, not a magic trick.
Our x86 model stores the least significant byte first. The four-byte value 0x12345678 appears at increasing memory addresses as 78 56 34 12. When a write changes just one byte, reconstruct the resulting integer from the full byte sequence.
This optional endian model becomes interactive with JavaScript. The lesson, explanations and checkpoint answer remain readable without it.
0x41414141 is four ASCII A bytes interpreted as an address. It is a familiar crash marker, not a universal promise that a process will fault at exactly that point. A partial overwrite, earlier fault or guard check can produce another outcome.
Crash, corruption, control: three different claims.
A segmentation fault can indicate an invalid memory access. An illegal-instruction fault can indicate decoding bytes that are not valid instructions. Neither alone explains the original write or proves reliable control. Trace the earliest invalid operation, not just the final symptom.
Next, follow the historical exploit chain and identify the extra assumptions it needs. If you are fixing the bug rather than studying it, skip to the bounded-copy example and regression tests.
Your turn. Call the outcome.
The source contains sixteen nonzero bytes followed by zero. strcpy copies it into char name[16]. How many bytes does it try to write?
Read the explanation
The terminator is copied too. Seventeen destination writes exceed a sixteen-byte object by one byte. Padding does not extend the object’s legal bounds.
Sources & what we changed
Based on the supplied text of Aleph One’s Smashing the Stack for Fun and Profit, Phrack 49, file 14, 8 November 1996. Original author credit remains with Aleph One. This independent OverWatch Labs explanation uses new prose, synthetic models and modern defensive notes; it is not endorsed by Phrack or the original author.
This lesson maps to: Buffer Overflows; example2.c; example3.c; Writing an Exploit. Historical examples are described, not represented as current product vulnerabilities. We correct byte-addressability, array padding, terminator counting and the supplied return-address arithmetic rather than reproducing those errors.
- Aleph One, Smashing the Stack for Fun and Profit, Phrack 49 (1996)
- MITRE CWE-121: Stack-based Buffer Overflow
Original shell-spawning byte arrays and platform-specific exploit drivers are replaced with symbolic models. The causal concepts are preserved; browser outcomes are not native exploitation evidence. Modern controls are editorial additions, not claims made by the 1996 paper.