Was ist Pufferüberlauf (Buffer Overflow)?

Schreiben von mehr Daten in einen Bereich wie ein Array (Puffer), als dessen Größe zulässt, wodurch benachbarter Speicher zerstört wird. In C passiert das leicht mit strcpy oder gets, die die Größe des Ziels nicht kennen, oder mit Schleifen, die Indizes ohne Bereichsprüfung verwenden, und es ist undefiniertes Verhalten. Läuft ein Puffer auf dem Stack über, werden lokale Variablen und die Rücksprungadresse der Funktion überschrieben, was für Angriffe missbraucht werden kann, bei denen eine Eingabe von außen beliebigen Code ausführen lässt. Abhilfe schaffen Funktionen mit Größenangabe und Bereichsprüfungen.

Japanische Bezeichnung: バッファオーバーフロー

„Pufferüberlauf (Buffer Overflow)“ kommt in 3 Übungsfragen aus 2 Themen vor, z. B. Linker, Loader und ausführbare Formate, Grundlagen der Programmiersprache C.

Fachgebiet: Grundlagen der Programmiersprache C

Häufige Ursachen

Typische Fehler sind: das abschließende '\0' nicht mitzuzählen und 8 Zeichen per strcpy in char name[8] zu kopieren, Eingaben ohne Längenprüfung mit gets oder scanf("%s") einzulesen oder wie in for (i = 0; i <= N; i++) ein Element zu viel zu schreiben. Bei Funktionen, die die Größe des Ziels nicht erhalten, bestimmen die Eingabedaten, wie viel geschrieben wird.

Missbrauch für Angriffe und Schutzmechanismen

In der Nähe eines Puffers auf dem Stack ist die Rücksprungadresse der Funktion gespeichert. Ein Angreifer überschreibt sie mit einer langen Eingabe und lenkt die Ausführung auf vorbereiteten Code oder auf Bibliotheksfunktionen um. Betriebssysteme und Compiler erschweren den Missbrauch durch Stack-Schutz (Canary), der einen vor der Rücksprungadresse abgelegten Wert auf Änderungen prüft, durch die Trennung von Schreiben und Ausführen (W^X) und durch die Randomisierung von Adressen (ASLR).

Vorbeugung im Programm

Statt strcpy verwendet man Funktionen wie snprintf, denen man die zu schreibende Größe angeben kann, und prüft Eingabelängen und Indexbereiche stets. Während der Entwicklung erkennt -fsanitize=address (AddressSanitizer) Schreibzugriffe außerhalb der Grenzen zur Laufzeit. Auf einem Mikrocontroller ohne MMU hält ein Überlauf nicht sofort an, sondern zerstört benachbarte Daten; hier ist besondere Vorsicht geboten.

Jetzt üben: Fragen zu Pufferüberlauf (Buffer Overflow)

Welche Aussage zum Zweck von ASLR (Address Space Layout Randomization) ist richtig?

  1. ADie Adressen von Stack, Heap, Bibliotheken usw. werden bei jeder Ausführung geändert, sodass die Zieladressen von Angreifern schwer vorhersagbar sind
  2. BSpeicheradressen werden zufällig gewählt, um die Cache-Trefferrate zu erhöhen
  3. CUngenutzter Speicher wird zufällig freigegeben, um den freien Platz zu vergrößern
Antwort und Erläuterung anzeigen

Antwort: A. Die Adressen von Stack, Heap, Bibliotheken usw. werden bei jeder Ausführung geändert, sodass die Zieladressen von Angreifern schwer vorhersagbar sind

Bei Angriffen, die z. B. Pufferüberläufe ausnutzen, ist es wichtig, die Adressen von Bibliotheksfunktionen und Daten auf dem Stack zu kennen. ASLR verschiebt bei jedem Prozessstart die Adressen, an denen Stack, Heap, Shared Libraries und die ausführbare Datei liegen, sodass Angreifer die Adressen nicht fest vorgeben können. Allein bietet es keinen vollständigen Schutz und wird mit weiteren Maßnahmen wie der Trennung von Schreiben und Ausführen kombiniert.

Welcher Angriff lässt sich leichter verhindern, wenn Speicherseiten nicht gleichzeitig „beschreibbar“ und „ausführbar“ sein dürfen (W^X, Trennung von Schreiben und Ausführen)?

  1. AEin Angriff, der Passwörter durch Ausprobieren aller Möglichkeiten testet
  2. BEin Angriff, der durch große Mengen an Datenverkehr einen Server lahmlegt
  3. CEin Angriff, der Angriffs-Maschinencode in Datenbereiche wie den Stack schreibt und dorthin springen und ihn ausführen lässt
Antwort und Erläuterung anzeigen

Antwort: C. Ein Angriff, der Angriffs-Maschinencode in Datenbereiche wie den Stack schreibt und dorthin springen und ihn ausführen lässt

Bei älteren Angriffen wurde häufig per Pufferüberlauf Maschinencode auf den Stack geschrieben und die Rücksprungadresse dorthin gelenkt, um ihn auszuführen. In der Seitentabelle der CPU gibt es ein Bit für Ausführungsverbot (z. B. das NX-Bit); macht das Betriebssystem Stack, Heap und .data nicht ausführbar und .text nicht beschreibbar, ist diese Methode nicht mehr nutzbar. Wird wie bei JIT-Compilern zur Laufzeit Code erzeugt, werden die Schreib- und Ausführungsrechte umgeschaltet.

Häufige Fragen

Hält ein Pufferüberlauf das Programm immer an?

Nicht unbedingt. Trifft der überzählige Schreibzugriff einen ungenutzten Bereich, scheint nichts zu passieren; zerstört er eine andere Variable, entstehen an ganz anderer Stelle falsche Ergebnisse. Mitunter bricht das Programm erst ab, wenn die Rücksprungadresse zerstört wurde oder der Stack-Schutz greift.

Ist strncpy sicher?

strncpy kopiert höchstens die angegebene Zahl von Zeichen, hängt aber bei einer zu langen Quelle kein abschließendes '\0' an, sodass nachfolgende Verarbeitung außerhalb der Grenzen lesen kann. Besser ist snprintf, das mit Größenangabe arbeitet und stets terminiert, oder man schreibt nach strncpy selbst einen Abschluss.

„Pufferüberlauf (Buffer Overflow)“ in den Erläuterungen

Fragen mit „Pufferüberlauf (Buffer Overflow)“ (3)

  1. Welche Aussage zum Zweck von ASLR (Address Space Layout Randomization) ist richtig?
  2. Welcher Angriff lässt sich leichter verhindern, wenn Speicherseiten nicht gleichzeitig „beschreibbar“ und „ausführbar“ sein dürfen (W^X, Trennung von Schreiben und Ausführen)?
  3. Der obigen Funktion save wird die Zeichenkette "ABCDEFGH" mit 8 Zeichen übergeben. Was passiert?

Verwandte Begriffe

Stack (Stapelspeicher) Heap Rücksprungadresse ASLR Seitentabelle (Page Table) Variable Ausrichtung und Auffüllung (Alignment und Padding) Bitfeld Dangling Pointer (hängender Zeiger) Dynamische Speicherreservierung

Zur Glossarübersicht