Lukas' Notes

security memory c

Definition

Stack Corruption

Stack corruption is the family of control-flow hijack attacks that exploits a buffer overflow on the stack to overwrite control data in the frame — local variables, function pointers, the saved base pointer, or the saved return address. All four subclasses share the same mechanism: writing past a local buffer walks upward into whatever sits adjacent in the frame; only the target of the overwrite differs.

The Four Subclasses

Four adjacent frame slots, four attacks

SubclassOverwritten targetEffect
local variable clobberinga neighbouring local variabledivert the immediate execution flow (e.g. flip a guard into a “Win” value)
function pointer clobberinga local function pointercompletely control the execution flow at the next indirect call
instruction pointer hijackingthe saved return addresscompletely control the execution flow when the function returns — see [[Knowledge/Instruction Pointer Hijacking
frame pointer hijackingthe saved base pointermove the caller’s frame to attacker-controlled memory — see [[Knowledge/Stack Pivot

The boundary between local variable clobbering and function pointer clobbering is just which adjacent slot the overflow reaches; the boundary between the two and the instruction/frame pointer cases is that the latter overwrite control data the CPU resumes through on return, rather than data the function reads.

Example: Local Variable Clobbering

Overflowing guard to reach the Win branch

int main(void) {
    long guard = 0xcabba6e5;
    char data[0x10] = {0};
    gets(data);
    if (guard == 0xb000000f) printf("Win \\o/\n");
    else                    printf("N00b :(\n");
    return 0;
}
  • the layout
    • data[0x10] sits at 0xf608, guard at 0xf618, the saved rbp at 0xf620, the saved rip at 0xf628
  • the intended behaviour
    • 0xb000000f is never written to guard by the program, so “Win \o/” should never print
  • the overflow
    • gets does not bound the read; supplying 0x10 bytes of A then 0xb000000f in little-endian walks the write from data into guard
  • the result
    • guard is now 0xb000000f, the if fires and “Win \o/” prints — the overflow turned a length bug into a privilege escalation through a single local variable

Example: Function Pointer Clobbering

Redirecting fptr from noob to win

void noob(void) { printf("N00b :(\n"); }
void win (void) { printf("Win \\o/\n"); }
int main(void) {
    void (*fptr)(void) = &noob;
    char data[0x10] = {0};
    gets(data);
    (*fptr)();
    return 0;
}
  • the layout
    • data at 0xf608, fptr at 0xf618 holding &noob, saved rbp/rip above
  • the intended behaviour
    • (*fptr)() calls noob, printing “N00b :(”
  • the overflow
    • gets overruns data and overwrites fptr with &win
  • the result
    • the indirect call (*fptr)() now dispatches to win — the attacker has full control of where the next call goes, without touching the saved return address

A function pointer gives the attacker complete control at the call site rather than at function return, which is what makes this subclass cleaner than local variable clobbering but harder to stage than instruction pointer hijacking.