- PaX
-
PaX ist ein Sicherheitspatch für den Linux-Betriebssystemkern, der einen „Geringste-Rechte“-Schutz (engl. least privilege) für Speicherseiten implementiert. Der Ansatz der geringsten Rechte erlaubt Computerprogrammen nur diejenigen Aktionen durchzuführen, die sie für einen ordentlichen, regulären Ablauf benötigen, und verbietet alle darüber hinausgehende. PaX wurde 2000 das erste Mal veröffentlicht.
PaX markiert Datenbereiche des Speichers als nicht-ausführbar und Programmbereiche als nichtbeschreibbar und ordnet den Programmspeicher zufällig an. Das erste verhindert direkte Code-Ausführung, während das letztere sog. return-to-libc-Angriffe (ret2libc) stark erschwert, ein Erfolg eines solchen Angriffes hängt dann vor allem vom Zufall ab; es verhindert aber nicht das Überschreiben von Variablen und Pointern.
PaX wurde durch das PaX Team geschrieben. Der Hauptautor von PaX möchte anonym bleiben.
Inhaltsverzeichnis
- 1 Bedeutung
- 2 Was PaX bietet
- 3 Distributionen, die PaX verwenden
- 4 Referenzen
- 5 Weblinks
Bedeutung
Viele, wenn nicht fast alle, Sicherheitslücken bei Computern sind auf Fehler in Programmen zurückzuführen, die es ermöglichen, die Funktion eines Programms zu verändern, effektiv also ein „Umschreiben“ des Programms während dessen Ausführung erlauben. So zeigen die ersten 44 Ubuntu Security Notices, dass 41 % der Angriffsmöglichkeiten aus buffer overflows resultieren, 11 % aus integer overflows und 16 % von anderer, falscher Behandlung von nicht erwartungsgemäßen Daten. Diese Typen von Programmfehlern ermöglichen es oft, Schadcode einzuschleusen und auszuführen; im Beispiel machen sie 61 % aus, ohne Berücksichtigung von Überschneidungen. Die oben durchgeführte Analyse ist sehr ungenau, eine umfangreichere Untersuchung würde sicherlich andere Zahlen ergeben (sowohl höher als auch tiefer), zeigt aber grundsätzlich die Problematik auf.
Viele Würmer, Viren und Übernahmeversuche beruhen auf der Veränderung von Speicherinhalten, so dass Schadcode ausgeführt wird; oder auf Ausführung von Speicherinhalten (durch Falschadressierung) die eigentlich Daten darstellen sollen. Wenn die Ausführung solcher Anweisungen verhindert werden könnte, würde solche Schadsoftware nur noch wenig bis gar keinen Schaden anrichten können, sogar nach Installation auf dem Computer; viele könnten überhaupt nicht mehr installiert werden (z. B. der Sasser-Wurm).
PaX wurde entworfen um genau dies für eine große Anzahl möglicher Angriffe zu tun, und dies auf einem sehr allgemeinen, breit anwendbarem Weg. Er verhindert die Ausführung von missbräuchlichem Code durch Kontrolle des Zugriffes auf den Speicher (lesen, schreiben, Zugriff auf Programmcode sowie Kombinationen davon) und dies, ohne die Ausführung von normalem Code zu verhindern. Mit einem kleinen Overhead reduziert PaX dadurch viele Exploits auf Denial of Service-Angriffe: Exploits, die dem Angreifer normalerweise root-Zugriff, Zugriff auf wichtige Daten oder anderen Schaden anzurichten erlauben würden, würden das betroffene Programm nunmehr abstürzen und das restliche System unbehelligt lassen.
Ein DoS-Angriff ist natürlich unangenehm und resultiert oft in Verlust von Zeit oder anderen Ressourcen; jedoch werden meistens keine Daten kompromittiert, wenn PaX eingreift. Trotzdem kann ein DoS-Angriff in gewissen Umgebungen absolut nicht akzeptabel sein; es gibt level-of-service-Verträge oder andere Bedingungen, die einen erfolgreichen Einbruch in ein System weniger kostenintensiv machen als die Reduktion oder Verlust der Verfügbarkeit eines Dienstes. In diesem Licht betrachtet ist der Ansatz von PaX nicht überall angemessen, in vielen Fällen jedoch ist es eine brauchbare Methode um vertrauliche Daten vor Sicherheitsbrüchen zu schützen.
Viele, aber nicht alle, Programmierfehler verursachen eine Verfälschung des Speicherinhaltes. Von den Fehlern, die dies ermöglichen und absichtlich herbeigeführt werden können, ermöglichen einige das Programm verschiedene Dinge durchführen zu lassen, für die es nicht vorgesehen wurde, wie z. B. eine privilegierte Shell zu erhalten. Der Fokus von PaX ist nicht das Finden und Korrigieren solcher Fehler, sondern das Verhindern und Isolieren der Exploits dieser Fehler. Wie im oberen Absatz angetönt, wird eine Untermenge dieser Fehler in ihrer Schwere heruntergestuft; Programme werden beendet statt ihre Dienste fehlerbehaftet weiterhin anzubieten.
PaX verhindert buffer-overflows nicht direkt. Stattdessen verhindert es, dass viele dieser und ähnlicher Programmierfehler ausgenutzt werden um unberechtigt Zugriff auf ein Computersystem zu erhalten. Andere Systeme wie Stack-Smashing Protector und StackGuard versuchen buffer-overflows direkt zu verhindern und das entsprechende Programm bei Entdeckung zu terminieren. Dieser Ansatz wird Stack-Smashing genannt und versucht die Angriffe abzuwehren bevor sie überhaupt durchgeführt werden können. Der allgemeinere Ansatz von PaX hingegen verhindert Schaden nachdem der Angriff beginnt. Obwohl beide Methoden dieselben Ziele erreichen können, sind sie nicht völlig redundant. Dadurch wird ein Betriebssystem bei Verwendung beider Methoden prinzipiell sicherer. Es gibt bereits Linux-Distributionen, die beide Methoden benutzen.
Einschränkungen
PaX kann Fehler im Design von Programmen oder des Kernels, die einen Missbrauch der angebotenen Funktionen erlauben, nicht verhindern. Diese Fehler sind im Prinzip so auch nicht feststellbar. Als Beispiel mag man einen Script-Interpreter betrachten, der Zugriff auf Dateien und Netzwerk erlaubt und diese Funktionen ungenügend schützt: Der Angreifer könnte auf Dateien von anderen Benutzern zugreifen, ohne dabei am Programm etwas „verbiegen“ zu müssen. PaX kann auch nicht alle Formatstring-Angriffe abwehren, die beliebiges Lesen und Schreiben in Datenbereiche des Speichers durch bereits existierenden Code erlauben; der Angreifer braucht weder interne Adressen zu wissen noch fremden Code einzuschleusen um diesen Typ Angriff durchführen zu können.
Die PaX-Dokumentation beschreibt die folgenden drei Klassen von Angriffen, vor denen PaX zu schützen versucht. Sie behandelt sowohl Angriffe, die PaX abwehrt, als auch solche, die nicht abgewehrt werden. Alle setzen ein vollständiges, positions-unabhängiges Programm mit Schutz des Programmspeichers und zufälliger Anordnung des Adressbereiches voraus. Folgende Angriffe können dann blockiert werden:
- Angriffe, die fremden Code einschleusen und ausführen,
- Angriffe, die existierenden Code nicht in dem vom Programmierer vorgesehenen Ablauf ausführen (ret2libc),
- Angriffe, die existierenden Code mit falschen Daten ausführen
Da das Ziel von PaX Schaden statt Angriffe zu verhindern ist, ist es nicht möglich, alle Angriffe zu verhindern. Genau betrachtet, ist es sogar logisch unmöglich, jeden Angriff zu verhindern (Satz von Rice).
- Die dritte Klasse ist trotz PaX 100 %-ig möglich, wenn der Angreifer keine Kenntnis von Adressen des angegriffenen Programms benötigt.
- Die zweite und dritte Klasse sind dann zuverlässig möglich, wenn der Angreifer zwar Kenntnis von Adressen benötigt, diese aber durch Auslesen des Adressbereiches des angegriffenen Programms erlangen kann. Dies ist möglich, wenn das Ziel einen entsprechenden Bug hat, der den Zugriff auf diese Informationen erlaubt, z. B. wenn der Angreifer Zugriff auf /proc/(pid)/maps hat.
Es existiert hierfür ein Patch, der alle Werte für Adressbereiche und Inodes in jeder Informationsquelle, die vom userland erreichbar ist, ausnullt. Dieser Patch ist zurzeit jedoch nicht in PaX enthalten.
- Die zweite und dritte Klasse sind mit geringer Erfolgswahrscheinlichkeit möglich, wenn der Angreifer Kenntnis von Adressen benötigt, diese aber nicht erhalten kann (brute-force und raten ausgenommen). Die ASLR-Dokumentation[1] beschreibt wie man die geringe Erfolgswahrscheinlichkeit genauer messen kann.
- Die erste Klasse ist möglich, wenn der Angreifer das Programm benutzen kann, um eine Datei anzulegen, zu beschreiben und via mmap() in den Speicher einblenden kann. Dies verlangt jedoch, dass die Angriffsmethoden der zweiten Klasse möglich sind; es gelten also dieselben Bedingungen wie ebenda beschrieben. Obwohl nicht Teil von PaX, wird unter anderem empfohlen, dass produktive Systeme Kontrollmechanismen einsetzen, die solche Angriffe verhindern.
Verantwortungsvolle Systemadministration ist trotz PaX immer noch notwendig. PaX verhindert oben beschriebene Angriffe, dennoch besteht die Möglichkeit eines erfolgreichen Angriffes.
Was PaX bietet
Schutz des Programmspeichers
Einer der Hauptmerkmale von PaX ist der Schutz von Programmbereichen des Speichers. Dieser Schutz verwendet das NX-Bit auf bestimmten Prozessoren um die Ausführung von fremden Code zu verhindern; dies fängt Angriffe ab, die auf Injektion von fremden Code oder Shellcode beruhen. Auf IA-32-CPUs ist das NX-Bit nicht vorhanden, PaX kann in diesem Fall dessen Funktionalität auf verschiedenen Wegen emulieren.
Viele Betriebssysteme, einschließlich Linux, nutzen das NX-Bit, falls vorhanden, um korrekte Einschränkungen auf den Speicher anzuwenden. Fig. 1 zeigt eine einfache Zusammenstellung von Speichersegmenten in einem Programm mit einer geladenen Bibliothek; grüne Segmente sind dabei Daten, blaue sind Programmcode. Unter normalen Umständen sieht der Adressbereich auf AMD64 und anderen derartigen Prozessoren ähnlich wie dieses Bild aus, mit klar definierten Daten- und Codesgmenten. Unglücklicherweise verwehrt Linux standardmäßig einem Programm nicht, seinen Speicherschutz zu ändern; jedes Programm kann Codesegmente als beschreibbar und Datensegmente als ausführbar kennzeichnen. PaX verhindert solche Änderungen, sowie es auch möglichst hohe Einschränkungen garantiert, die eine normale Ausführung erlauben.
Wenn die verschiedenen Schutzvorkehrungen des Programmspeichers aktiviert sind, einschließlich der mprotect()-Einschränkungen, garantiert PaX, dass keinerlei Speicherzuordnungen in irgendeiner Weise als ausführbarer Programmcode markiert werden können nachdem es möglich gewesen wäre den Zustand dieser Bereiche zu ändern. Der Effekt dieser Maßnahme ist, dass es unmöglich wird, Speicherbereiche auszuführen während oder nachdem sie verändert werden können, bis diese Bereiche schließlich wieder freigegeben werden; und damit, dass kein Code in das Programm eingeführt werden kann, ob nun schädlich oder nicht, weder von einer internen noch einer externen Quelle.
Die Tatsache, dass Programme Datenbereiche nicht ausführen können, obwohl die dort gespeicherten Daten dafür vorgesehen wären, stellt ein unüberwindbares Problem für ebendiese Programme dar. Ein Beispiel hierfür sind die Just-in-time-Compiler für Java; jedoch können viele dieser Programme vom Programmierer so geändert werden, dass sie nicht auf dieser Funktionalität beruhen. Die anderen können durch den Systemadministrator gekennzeichnet werden, PaX wendet dann die Einschränkungen für diese nicht an.
Das PaX-Team musste einige Entscheidungen im Bezug auf die Behandlung des mmap()-Aufrufes treffen. Diese Funktion wird dazu verwendet, gemeinsamen Speicher (shared memory) abzubilden oder dynamische Bibliotheken (shared libraries) zu laden. Aufgrund dessen benötigt der Aufruf beschreibbare oder ausführbare Speicherbereiche, abhängig von den jeweiligen Bedingungen.
Die aktuelle Implementation von PaX unterstützt beschreibbare anonyme Speicherabbildungen standardmäßig; beschreibbare Abbildungen einer Datei sind nur beschreibbar, wenn der mmap()-Aufruf das Schreibrecht angibt. Es werden jedoch nie Abbildungen zurückgegeben, die beschreib- und ausführbar sind; sogar wenn der Aufruf diese Rechte explizit angibt.
Erzwungen nicht-ausführbare Speicherseiten
PAGEEXEC
SEGMEXEC
Eingeschränktes mprotect()
"Trampoline"-Emulation
Zufällige Anordnung des Adressbereiches
Zufällige Stack-Basisadresse
Zufällige mmap()-Basisadresse
Zufällige ET_EXEC-Basisadresse
Kennzeichnung von Programmen
Distributionen, die PaX verwenden
- Gentoo mit gepatchtem Kernel (sys-kernel/hardened-sources).
Referenzen
Weblinks
Kategorien:- Linux-Software
- IT-Sicherheit
Wikimedia Foundation.