Programming lesson
Format-String-Angriff in C: Schritt-für-Schritt-Anleitung für CSCI 180
Lerne, wie ein Format-String-Angriff in C funktioniert – von der Deaktivierung von ASLR bis zum Überschreiben von Speicher mit %n. Inklusive Stack-Frame-Analyse und praktischen Beispielen.
Einführung in Format-String-Schwachstellen
Format-String-Schwachstellen treten auf, wenn ein Programm Benutzereingaben direkt als erstes Argument an printf() übergibt, ohne einen Format-String zu spezifizieren. Statt printf("%s", input) schreibt der Entwickler printf(input). Dies ermöglicht es einem Angreifer, Speicher auszulesen oder zu überschreiben. In diesem Tutorial zeigen wir dir Schritt für Schritt, wie du eine solche Schwachstelle ausnutzt – basierend auf der Übung CSCI 180 – Computer Security.
Vorbereitung: ASLR deaktivieren
Bevor wir beginnen, deaktivieren wir die Address Space Layout Randomization (ASLR), um die Angriffe reproduzierbar zu machen. Führe folgenden Befehl aus:
sudo sysctl -w kernel.randomize_va_space=0Prüfe die Einstellung mit:
sysctl -a --pattern randomizeDer Wert sollte 0 sein. Denke daran: Diese Änderung ist temporär. Nach einem Neustart musst du sie erneut durchführen.
Den verwundbaren Code kompilieren
Kompiliere die bereitgestellte vul.c mit der Option -m32 für 32-Bit:
gcc -m32 vul.c -o vulNimm an, dass du nur Lese-/Ausführungsrechte hast, aber den Quellcode einsehen kannst.
Task 1: Programm verstehen und zum Absturz bringen
Die Format-String-Schwachstelle identifizieren
Sieh dir vul.c an. Die Schwachstelle befindet sich in der Zeile, die printf(buffer) aufruft, wobei buffer die Benutzereingabe ist. Notiere diese Zeile für deinen Bericht.
Stack-Frame skizzieren
Zeichne einen Stack-Frame, der die Funktionsaufrufe myprint() und printf() zeigt. Markiere die Position des Format-Strings und der lokalen Variablen. Dies hilft dir, die späteren Schritte zu verstehen.
Das Programm zum Absturz bringen
Gib eine Zeichenkette ein, die viele %x- oder %s-Format-Spezifizierer enthält, um einen Segmentation Fault zu provozieren. Beispiel:
%x.%x.%x.%x.%x.%x.%x.%xDas Programm wird versuchen, Werte vom Stack zu lesen, was irgendwann zu einer illegalen Speicheradresse führt. Dokumentiere deine Eingabe und das Ergebnis mit einem Screenshot.
Task 2: Speicherwerte anzeigen und Stack-Frame vervollständigen
Dein Ziel ist es, mit %x-Spezifizierern den Inhalt des Stacks auszulesen. Die Variable target = 0x11111111 dient als Marker. Wenn du die richtige Anzahl von %x verwendest, erscheint 11111111 in der Ausgabe. So bestimmst du, wie viele Werte zwischen den Stack-Frames von printf() und myprint() liegen.
Beispiel-Eingabe (mit 8 %x):
AAAA.%x.%x.%x.%x.%x.%x.%x.%xSuche nach 11111111 in der Ausgabe. Die Position verrät dir den Offset. Vervollständige deine Stack-Frame-Zeichnung mit den zusätzlichen Werten.
Task 3: Eine Ganzzahl in den Speicher schreiben
Nun nutzen wir %n, um die Anzahl der bereits ausgegebenen Zeichen an eine Adresse zu schreiben. Wir wollen den Wert der Variablen target ändern. Dazu benötigen wir ihre Speicheradresse. Im Code wird diese ausgegeben – ein „Cheat“, den echte Angreifer anderweitig ermitteln müssten.
Eingabe mit Adresse erstellen
Da die Adresse Binärbytes enthält, die nicht über die Tastatur eingegeben werden können, schreiben wir sie in eine Datei. Angenommen, target hat die Adresse 0xffbfcd05 (Little-Endian: \x05\xcd\xbf\xff). Erstelle die Eingabedatei mit:
echo $(printf "\x05\xcd\xbf\xff").%x.%x.%x.%x.%x.%x.%x.%n > inputfileDie %n am Ende schreibt die Anzahl der bisher ausgegebenen Zeichen an die Adresse, die am Anfang des Strings steht. Führe das Programm aus:
./vul < inputfileIn der Ausgabe siehst du den Wert von target vor und nach dem Angriff. Der neue Wert ist die Anzahl der Zeichen, die vor %n ausgegeben wurden. Wenn du z. B. 100 Zeichen ausgibst, wird target auf 100 (0x64) gesetzt. Du kannst die Anzahl durch zusätzliche Format-Spezifizierer oder Padding steuern.
Erklärung von %n
%n schreibt die Anzahl der bereits mit printf ausgegebenen Zeichen als Integer an die Adresse, die als nächstes auf dem Stack liegt. Indem du die Adresse von target an den Anfang deines Strings setzt, überschreibst du deren Wert. Dies ist ein mächtiges Werkzeug, um beliebige Speicherstellen zu manipulieren.
Trend-Verbindung: Warum Format-String-Angriffe heute noch relevant sind
Obwohl Format-String-Schwachstellen weniger häufig vorkommen als früher, tauchen sie immer wieder in Legacy-Code oder eingebetteten Systemen auf. In der Welt der KI-gestützten Sicherheitsanalyse und Bug Bounties sind solche Low-Level-Kenntnisse Gold wert. Ähnlich wie beim Reverse Engineering von Spiele-Cheats (z. B. in Valorant oder Fortnite) hilft das Verständnis von Stack und Speicher dabei, Sicherheitslücken zu finden. Auch in der Finanz-App-Entwicklung (z. B. Trade Republic oder N26) sind sichere Programmierpraktiken essenziell, um Kundendaten zu schützen.
Zusammenfassung
Du hast gelernt, wie man eine Format-String-Schwachstelle erkennt, ASLR deaktiviert, das Programm zum Absturz bringt, Speicher ausliest und schließlich eine beliebige Ganzzahl schreibt. Diese Techniken sind grundlegend für das Verständnis von Binary Exploitation und Ethical Hacking. Übe sie in einer kontrollierten Umgebung, um deine Fähigkeiten in der Cybersicherheit zu vertiefen.