Ein Haufen Risiko

Fast jedes zweite kritische Sicherheitsleck beruht auf einem Heap-Overflow. Über derartige Fehler kann ein Angreifer beliebigen Code einschleusen und ausführen. Selbst scheinbar harmlose Bilddateien mutieren damit zum gefährlichen Trojanischen Pferd.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 32 Min.
Von
  • Felix "FX" Lindner
Inhaltsverzeichnis

Das Betrachten einer Bilddatei sollte eigentlich ein harmloser Vorgang sein, von dem man nicht erwarten würde, dass man sich dabei einen Virus oder Trojaner einfangen kann. Schließlich wird ja kein Programmcode ausgeführt, sondern der Bildbetrachter interpretiert lediglich die Daten der Bilddatei, um ein paar Pixel auf dem Bildschirm einzufärben. Fehlerhafte Dateien resultieren normalerweise in Pixelsalat auf dem Bildschirm; mehr Schaden richten sie nicht an.

Wenn aber das Anzeigeprogramm nachlässig programmiert ist, können unzulässige Datenstrukturen in der Bilddatei zu einem Pufferüberlauf führen: Daten belegen mehr Platz, als der Programmierer vorgesehen hat und überschreiben Speicherplätze, an denen sie nichts verloren haben. Die harmloseste Folge wäre, dass das Programm in der Folge so durcheinanderkommt, dass ihm das Betriebssystem auf die Finger klopft und es beendet. Der Sicherheits-GAU tritt ein, wenn es durch gezielt manipulierte Bilddateien möglich ist, Maschinencode ins System einzuschleusen, den der Bildbetrachter dann zur Ausführung bringt, wie es beispielsweise ein Fehler in der Windows-Bibliothek gdiplus.dll bei der Anzeige von JPG-Dateien ermöglichte. Dieses konkrete Ausnutzen eines Programmfehlers für bösartige Zwecke bezeichnet man in der Sicherheitsszene als Exploit.

Pufferüberläufe (englisch: buffer overflow) sind ein grundsätzliches Sicherheitsrisiko, das nicht nur im Zusammenhang mit Bilddateien auftreten kann, sondern potenziell immer, wenn eine Anwendung nicht vertrauenswürdige Daten interpretiert und der Programmierer dabei etwas nicht bedacht hat. Je nachdem, in welchem Datenbereich der Überlauf stattfindet, spricht man von Stack- oder Heap-Overflow. Da diese Fehler früher hauptsächlich auf dem Stack gefunden und ausgenutzt wurden, hat es sich einbürgert, nur für diese Gattung den allgemeinen Begriff Buffer-Overflow zu verwenden.

Doch eigentlich gehören auch die mittlerweile mehr in Mode gekommenen Heap-Overflows in diese Kategorie. Wer es noch genauer nimmt, sollte von Buffer-Overflows auf dem Heap sprechen, da keineswegs der Heap selbst überläuft, sondern lediglich ein dort abgelegter Puffer. Im Folgenden kommt jedoch meist die etablierte Kurzbezeichnung Heap-Overflow zum Einsatz.

Um zu verstehen, wie sich ein Heap-Overflow auswirkt und vor allem, wie er sich ausnutzen lässt, ist zunächst ein kleiner Ausflug in die Speicherverwaltung notwendig. Variablen – und damit auch Puffer – kann ein Programm an drei recht unterschiedlichen Stellen im Speicher anlegen: dem Datenbereich, dem Stack und dem Heap. Der Datenbereich enthält statische Variablen. Zwar können auch die sich zur Laufzeit ändern und somit Angriffsfläche bieten; doch reale Angriffe durch Buffer-Overflows gibt es hier kaum.

Auf dem Stack vermischen sich Verwaltungsinformationen mit Nutzdaten des Programms.

Lokale Variablen in C-Funktionen, die Programmierer gern als Puffer für Eingabedaten verwenden, legt der Compiler auf dem Stack an. Der Stack hat eine weitere wichtige Funktion: Hier sichert die CPU die Rücksprungadresse, wenn sie eine Unterfunktion aufruft. Wenn ein Angreifer diese Adresse durch einen Pufferüberlauf gezielt mit einem anderen Wert überschreiben kann, führt die CPU das Programm nach dem Abarbeiten der Funktion an der gespeicherten Rücksprungadresse weiter aus. Nur handelt es sich dabei nicht mehr um den Originalwert, sondern um einen Zeiger auf den eingeschleusten Code. Ein Exploit ist geboren.

Das grundlegende Problem ist, dass die Systeme Programmvariablen und Puffer mit Verwaltungsdaten mischen. So kann ein Überlauf der Programmdaten auch Managementinformationen überschreiben und damit unerwarteten Einfluss auf den Programmablauf nehmen. Nur deshalb gelingt es relativ einfach, den Programmfluss mit Hilfe eines Buffer-Overflow zu ändern und Code des Angreifers ausführen zu lassen. Dieses generelle Verhalten kann der Programmierer nicht ändern; er hat keinen Einfluss darauf, wo beispielsweise die CPU Rücksprungadressen speichert.