Overflow minimal

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen

Buffer Overflow: Die unsichtbare Gefahr in 6 Bytes

Kurzbeschreibung

Dieses Lehrbeispiel zeigt, wie ein unsicherer Kopiervorgang in C bei einem 6-Byte-Puffer zu einem Stack-Buffer-Overflow und damit zu einem Absturz führen kann. Nur Analyse/Lehre in einer isolierten VM. Kein Exploit.

Voraussetzungen

Debian/Ubuntu oder eine ähnliche Linux-Distribution mit gcc, gdb und python3.

Beispielcode (kopierbar)

  • cat overflow_minimal.c
 /* overflow_minimal.c - Buffer Overflow Demonstration */
 #include <stdio.h>
 #include <string.h>

 void func(char *input)
 {
     char buffer[6];   // Nur 6 Bytes Puffer (einschließlich NUL)
     strcpy(buffer, input);  // Absichtlich unsicher: keine Längenprüfung
     printf("Du hast eingegeben: %s\n", buffer);
 }

 int main(int argc, char *argv[])
 {
     if (argc < 2) {
         printf("Usage: %s <input>\n", argv[0]);
         return 1;
     }
     func(argv[1]);
     return 0;
 }

Kompilieren

Stack-Protector deaktiviert, Debug-Symbole aktiv:

  • gcc -fno-stack-protector -z execstack -g -o overflow_minimal overflow_minimal.c

Analyse mit AddressSanitizer:

  • gcc -g -fsanitize=address -fno-omit-frame-pointer -o overflow_minimal_asan overflow_minimal.c

Testen

Normale Eingabe (≤ 6 Zeichen):

  • ./overflow_minimal ABCDEF
Ausgabe: Du hast eingegeben: ABCDEF
  • echo $?
0

Kurze Überschreitung (7 Zeichen):

  • ./overflow_minimal ABCDEFG
Du hast eingegeben: ABCDEFG
Segmentation fault
  • echo $?
139

Analyse mit GDB

Das GNU Debugger (gdb) ist ein Werkzeug, um den Programmablauf zu verstehen und Fehler (wie hier durch Buffer Overflow) gezielt zu untersuchen. Alle folgenden Schritte dienen der Analyse, nicht der Ausnutzung.

  • gdb --args ./overflow_minimal "$(python3 -c 'print("A"*200)')"
 # Startet gdb mit dem Programm und einem 200-Byte-String als Argument.
  • run
 # Programm starten
  • bt
 # Backtrace anzeigen (zeigt Aufrufkette zum Absturz)
  • info registers
 # Registerstatus (RIP, RSP, RBP usw.)
  • frame 0
 # In das aktuelle Stackframe wechseln
  • info locals
 # Lokale Variablen (z. B. buffer) anzeigen
  • x/64bx $rsp
 # 64 Bytes Speicher ab Stackpointer anzeigen (hex)
  • x/s $rsp
 # Speicher als String anzeigen
  • disassemble func
 # Assemblercode der Funktion anzeigen

Erklärung der wichtigsten GDB-Befehle

  • run
 Startet das Programm unter gdb-Kontrolle. Stoppt bei Absturz (Segmentation fault).
  • bt
 Zeigt die komplette Aufrufkette vom main() über func() bis zur Absturzstelle.
  • info registers
 Zeigt CPU-Register an, z. B. rip (Instruktionszeiger), rbp/rsp (Stackpointer). Überprüfen, ob der Overflow Rücksprungadressen überschrieben hat.
  • x/64bx $rsp
 Dump des Stackinhalts (64 Bytes, Byteweise). Praktisch, um zu sehen, wie der Eingabestring den Stack überschreibt.
  • x/s $rsp
 Speicher als String anzeigen. Hier erkennt man oft endlose "A"-Zeichen bei Overflow.
  • info frame
 Zeigt Stackframe-Größe, Rücksprungadresse und Lage der lokalen Variablen.
  • disassemble func
 Zeigt CPU-Instruktionen der Funktion func. Hilfreich, um den Absturzpunkt zu lokalisieren.
  • break func
 Setzt einen Breakpoint vor der gefährlichen Stelle.
  • next / step / finish
 next: nächste Zeile ausführen, step: Funktionsaufruf betreten, finish: Funktion bis Ende ausführen.
  • info locals / info args
 Zeigt lokale Variablen und Funktionsargumente an, z. B. den Inhalt von buffer.
  • print buffer
 Inhalt von Variablen anzeigen.
  • x/32x $rbp-0x20
 Zeigt Stackbereich unterhalb des Framepointers, um zu sehen, wie viele Bytes überschrieben wurden.

Beispielanalyse

  • gdb --args ./overflow_minimal "$(python3 -c 'print("A"*40)')"
  • run
 Program received signal SIGSEGV, Segmentation fault.
  • bt
  #0  func (input=0x7fffffffde80 "AAAAAAAAAAAA...") at overflow_minimal.c:9
  #1  0x00005555555551a2 in main (argc=2, argv=0x7fffffffe2d8) at overflow_minimal.c:18
  • info registers
  rip = 0x4141414141414141  ← Rücksprungadresse durch "AAAA" überschrieben
  • x/32bx $rsp
  0x7fffffffdc80: 0x41 0x41 0x41 0x41 ...
 → Der Stack wurde mit 0x41 (ASCII 'A') gefüllt – typisches Overflow-Symptom.

Weitere nützliche Befehle

  • x/200bc $rsp → zeigt 200 Bytes als char
  • x/10i $rip → zeigt 10 Instruktionen ab aktueller Codeadresse
  • info proc mappings → zeigt Speicherbereiche (Text, Stack, Heap)
  • quit → gdb beenden

Sicherer Fix (Kontrast)

 void func_safe(char *input)
 {
     char buffer[6];
     snprintf(buffer, sizeof buffer, "%s", input);
     printf("Du hast eingegeben: %s\n", buffer);
 }

Fazit

  • Schon minimale Programmierfehler können massive Sicherheits- oder Stabilitätsprobleme verursachen.
  • Sorgfalt bei Puffergrößen, Eingabevalidierung und das Nutzen moderner Schutzmechanismen sind Pflicht in der sicheren Softwareentwicklung.
  • gdb ist ein starkes Werkzeug, um den Ablauf zu verstehen: Stack-Frames, Register und Speicher lassen sich genau untersuchen.
  • AddressSanitizer ist die sichere Alternative für automatische Overflow-Erkennung.