Overflow minimal: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
 
(4 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 11: Zeile 11:
 
   #include <stdio.h>
 
   #include <stdio.h>
 
   #include <string.h>
 
   #include <string.h>
 
+
 
   void func(char *input)
 
   void func(char *input)
 
   {
 
   {
Zeile 31: Zeile 31:
 
== Kompilieren ==
 
== Kompilieren ==
 
Stack-Protector deaktiviert, Debug-Symbole aktiv:
 
Stack-Protector deaktiviert, Debug-Symbole aktiv:
*gcc -fno-stack-protector -z execstack -g -o overflow_minimal overflow_minimal.c
+
* gcc -fno-stack-protector -z execstack -g -o overflow_minimal overflow_minimal.c
 
Analyse mit AddressSanitizer:
 
Analyse mit AddressSanitizer:
*gcc -g -fsanitize=address -fno-omit-frame-pointer -o overflow_minimal_asan overflow_minimal.c
+
* gcc -g -fsanitize=address -fno-omit-frame-pointer -o overflow_minimal_asan overflow_minimal.c
  
 
== Testen ==
 
== Testen ==
 
Normale Eingabe (≤ 6 Zeichen):
 
Normale Eingabe (≤ 6 Zeichen):
*./overflow_minimal ABCDEF
+
* ./overflow_minimal ABCDEF
 
  Ausgabe: Du hast eingegeben: ABCDEF
 
  Ausgabe: Du hast eingegeben: ABCDEF
*echo $?
+
* echo $?
 
  0
 
  0
 
Kurze Überschreitung (7 Zeichen):
 
Kurze Überschreitung (7 Zeichen):
*./overflow_minimal ABCDEFG
+
* ./overflow_minimal ABCDEFG
 
  Du hast eingegeben: ABCDEFG
 
  Du hast eingegeben: ABCDEFG
 
  Segmentation fault
 
  Segmentation fault
*echo $?
+
* echo $?
 
  139
 
  139
  
== Beobachtbares Verhalten ==
+
== Analyse mit GDB ==
* Kurze Überläufe überschreiben zunächst nur lokale Daten; der Absturz kann verzögert auftreten.
+
Das GNU Debugger (gdb) ist ein Werkzeug, um den Programmablauf zu verstehen und Fehler (wie hier durch Buffer Overflow) gezielt zu untersuchen. 
* Lange Eingaben überschreiben meist die Rücksprungadresse und führen zu SIGSEGV.
+
Alle folgenden Schritte dienen der Analyse, nicht der Ausnutzung.
* Mit ASAN-Kompilation erhältst du eine klare Meldung („stack-buffer-overflow“) mit Backtrace.
+
 
 +
* 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.
  
== Analyse mit GDB ==
+
* disassemble func 
* Beispiel:
+
  Zeigt CPU-Instruktionen der Funktion func. Hilfreich, um den Absturzpunkt zu lokalisieren.
  gdb --args ./overflow_minimal "$(python3 -c 'print(\"A\"*200)')"
+
 
  # in gdb: run
+
* break func 
   # nach Crash: bt
+
  Setzt einen Breakpoint vor der gefährlichen Stelle.
  # nützliche Befehle: bt, info registers, x/32x $rsp, disas
+
 
* Trainer-Hinweis: Stack-Layout (saved RBP, return address, lokale Variablen) erläutern.
+
* 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) ==
 
== Sicherer Fix (Kontrast) ==
Zeile 72: Zeile 138:
 
* Schon minimale Programmierfehler können massive Sicherheits- oder Stabilitätsprobleme verursachen.
 
* 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.
 
* 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.

Aktuelle Version vom 3. November 2025, 20:22 Uhr

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.