Buffer Overflows & Exploit Development

Tiefgehende Anleitung zur Sicherheitslücke Buffer Overflow und wie man sie ausnutzt.

Einführung: Was ist ein Buffer Overflow?

Ein Buffer Overflow entsteht, wenn ein Programm mehr Daten in einen Speicherbereich (Buffer) schreibt, als vorgesehen. Die überflüssigen Daten überschreiben benachbarte Speicherbereiche, möglicherweise auch Kontrolldaten wie Rücksprungadressen.

Diese Schwachstelle tritt häufig in C/C++ Programmen auf, wenn Funktionen wie gets(), strcpy() oder sprintf() verwendet werden.

Technischer Hintergrund – Stack-Funktion

Der Stack speichert lokale Variablen, Rücksprungadressen und alte Register. Er wächst im Speicher von oben nach unten.

  [ Puffer (z.B. 64 Bytes) ]
  [ gespeicherter Frame-Pointer ]
  [ Rücksprungadresse ]
      

Ein Buffer Overflow zielt darauf ab, mehr als die vorgesehenen Bytes zu schreiben, um die Rücksprungadresse zu überschreiben.

Exploit-Kette

Ziel ist es, den Programmfluss umzuleiten, indem man die Rücksprungadresse überschreibt. Schritte:

  1. Schwachstelle finden
  2. Offset zur Rücksprungadresse bestimmen
  3. Zieladresse (Funktion oder Shellcode) ermitteln
  4. Payload bauen und das Programm zur Ausführung bringen

Hands-on: Exploit-Demo

  #include <stdio.h>
  #include <string.h>
  
  void secret() { system("/bin/sh"); }
  void vulnerable() { char buffer[64]; gets(buffer); }
  
  int main() { vulnerable(); return 0; }
      

Kompilieren:

gcc -fno-stack-protector -z execstack -no-pie bof.c -o bof

Overflow provozieren:

python3 -c "print('A'*80)" | ./bof

Mit GDB Adresse von secret() herausfinden und in Little Endian formatieren.
Payload: 72 Bytes Füllung + Adresse von secret().

Schutzmechanismen

Viele Schutzmaßnahmen lassen sich z. B. mit ROP-Techniken umgehen.

Reale Beispiele

Diese Vorfälle zeigen, wie kritisch diese Schwachstellen auch heute noch sind.

Erweiterte Techniken

Tools: pwndbg, radare2, Ghidra, IDA Pro, pwntools

Fazit & Erkenntnisse

Praxis-Tipps für sichere Programmierung

Vermeiden Besser verwenden
gets() fgets()
strcpy() strncpy()
sprintf() snprintf()

Immer Eingaben validieren, keine festen Puffergrößen ohne Überprüfung verwenden.