Suchen

Libsafe und andere Tools Buffer Overflows in C-Programmen verhindern

Autor / Redakteur: Marcell Dietl / Stephan Augsten

Funktionsaufrufe in C können schnell zum Pufferüberlauf führen. Solche Fehler lassen sich mit dem Tool Libsafe und auf anderem Wege reduzieren. Moderne Betriebssysteme setzen zusätzlich auf Technologien wie Address Space Layout Randomization, kurz ASLR.

Firma zum Thema

Bei der Programmierung in C sind Programmierfehler, die Overflows provozieren, keine Seltenheit.
Bei der Programmierung in C sind Programmierfehler, die Overflows provozieren, keine Seltenheit.
(Bild: kuszapro - Pixabay.com / CC0 )

Die Programmiersprache C ist für systemnahe bzw. hochperformante Anwendungen häufig die erste Wahl. Leider sind viele Funktionen extrem fehleranfällig, von der Benutzung manch einer wird sogar offen abgeraten, auf der Linux man page heißt es beispielweise schlicht „Never use gets()“. Das Tool Libsafe kann unsichere Bibliotheksfunktionen allerdings abfangen.

Funktionen wie strcpy(), strcat(), scanf(), sprintf() und weitere haben alle eines gemein: Fehlendes Bounds Checking (Grenzwert-Kontrolle). Ankommende Daten lassen sich nicht direkt begrenzen und werden auch dann in den Zielpuffer kopiert, wenn dieser viel zu klein ist. Das Ergebnis ist ein klassischer Buffer Overflow.

Kritisch wird es dann, wenn die Daten vom Anwender stammen und dieser sie so manipuliert, dass der Programmfluss gezielt verbogen wird. Um derartige Fehler abzufangen, bedient sich Libsafe der Umgebungsvariable LD_PRELOAD. In dieser lassen sich dynamisch ladbare Bibliotheken angeben, deren Funktionen beim Start einer ELF-Datei Vorrang genießen sollen.

Mit Hilfe dieses Tricks „überschreibt“ Libsafe einzelne unsichere Standard-C-Funktionen mit Alternativen, welche den Prozess im Falle eines Pufferüberlaufs sofort stoppen. So lässt sich möglicher Schaden immerhin begrenzen; die Ursache des Problems bleibt jedoch weiterhin bestehen.

Stack-Overflows mit Compiler-Erweiterungen unterbinden

Durch die berühmt-berüchtigte Anleitung „Smashing The Stack For Fun And Profit“ von Aleph One, wurde 1996 erstmals einer breiten Öffentlichkeit das Problem von Buffer Overflows bewusst gemacht. Nur zwei Jahre später stellten Forscher auf dem USENIX Security Symposium eine Lösung vor: StackGuard. Wichtigster Bestandteil dieser Erweiterung des GNU C Compilers war die Einführung eines so genannten „Canary“.

Dieses wird zu Anfang einer jeden Funktion im Speicher platziert und vor dem abschließenden Rücksprung erneut überprüft. Ist der Wert des „Canary“ anders als anfangs gesetzt, deutet alles auf einen Pufferüberlauf hin und StackGuard beendet den Prozess.

Wegen diverser Schwächen wurde das Projekt nie offiziell Teil von GCC. Stattdessen wurde der Stack-Smashing Protector (SSP) von IBM mit Version 4.1 der GNU Compiler Collection auf breiter Basis etabliert. Dieser beseitigte viele Schwächen der ursprünglichen StackGuard-Implementation der Canary-Methode und führte weitere Schutzmechanismen ein.

Was bei Linux „Canary“ heißt, nennt sich bei Microsoft „Security Cookie“ und wird über die Compiler-Option /GS aktiviert. Technisch betrachtet sind sich die beiden Konzepte sehr ähnlich. Ihr Hauptziel ist der Schutz der auf dem Stack abgelegten Verwaltungsinformationen wie der Rücksprungadresse. Vor anderen Angriffstechniken wie Heap- oder BSS-Overflows schützt jedoch weder das „Canary“ noch das „Security Cookie“.

Nur zusammen mit ASLR bietet DEP ausreichend Schutz

Die bislang vorgestellten Maßnahmen versuchten stets zu erkennen, ob ein Puffer übergelaufen war, um den Prozess anschließend zu stoppen. Das von Microsoft Data Execution Prevention (DEP) genannte Konzept verfolgt einen komplett anderen Ansatz. Anstatt den Buffer Overflow zu verhindern, sorgt DEP dafür, dass vom Angreifer eingeschleuster Shellcode nicht ausgeführt werden kann.

Um ein Speichersegment als nicht ausführbar zu markieren, verfügen moderne CPUs über ein spezielles Bit, welches bei AMD NX- (No eXecute) und Intel XD-Bit (eXecute Disable) heißt. Versucht ein Angreifer dennoch eigenen Code im Speicher zu starten, führt dies zu einem Hardware-Interrupt, der den Prozess stoppt.

Zunächst schien die Gefahr von Buffer Overflows tatsächlich gebannt. Es dauerte jedoch nicht allzu lange bis Exploits auftauchten, die auch ohne das Einschleusen eigenen Codes reibungslos funktionierten. Dazu legten sie präparierte Werte auf dem Stack ab und verbogen den Programmfluss dergestalt, dass Standard-C-Funktionen wie system() gestartet werden. Diese fanden dann die vom Angreifer hinterlegten Parameter vor und verwendeten sie.

Gegen diese als Return-into-libc bezeichnete Technik ist der von DEP gewählte Ansatz leider machtlos. Nicht jedoch ASLR! Wie es der Name schon vermuten lässt, sorgt Address Space Layout Randomization dafür, dass der Adressbereich des Prozesses (möglichst) zufällig gewählt wird. So wird es für einen Angreifer schier unmöglich den genauen Ort einer Funktion wie system() zu kennen und der Exploit verläuft im Sande.

Alternative Sprachen mit automatischem Bounds Checking

Ein vollkommen anderer Ansatz, um Pufferüberläufe und weitere C-typische Fehler zu vermeiden, ist der Wechsel zu einer moderneren Sprache. Java- oder .NET-Programme führen automatisch Bounds Checking durch, sodass Buffer Overflows sofort abgefangen werden. Bei Skriptsprachen wie PHP, Perl, Python und anderen sieht die Lage ähnlich positiv aus.

Leider kann die Programmiersprache gerade bei größeren Projekten selten frei und willkürlich gewählt werden, sondern ist vielmehr an Abhängigkeiten und Bedingungen geknüpft. Darüber hinaus hat jede Sprache eigene Stolpersteine, die sich als genauso gefährlich erweisen können wie übergelaufene Puffer.

Mit dem Java Native Interface (JNI) ist es sogar möglich, von Bibliotheksfunktionen außerhalb der virtuellen Maschine Gebrauch zu machen. Über diesen Umweg könnten sich dann auch wieder alle möglichen Bugs einschleichen.

Und letzten Endes sind die Interpreter und virtuellen Maschinen der vielen modernen Programmiersprachen meist selbst in C oder C++ geschrieben und somit auch vor den genannten Risiken nicht gefeit.

(ID:44361124)