Assignment Chef icon Assignment Chef
All German tutorials

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.

Format-String-Angriff CSCI 180 Computer Security Format-String-Schwachstelle Stack-Frame Analyse ASLR deaktivieren Binary Exploitation Ethical Hacking Speicher auslesen Speicher überschreiben printf Schwachstelle Cybersicherheit Tutorial Format String Exploit C Programmierung Sicherheit Little Endian Adresse Bug Bounty Vorbereitung

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=0

Prüfe die Einstellung mit:

sysctl -a --pattern randomize

Der 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 vul

Nimm 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.%x

Das 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.%x

Suche 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 > inputfile

Die %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 < inputfile

In 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.