0. Technische Aspekte von Mac OS X Inhaltsverzeichnis

0.7 Einordnung von userland execve()

Was userland execve() ist und was es bezüglich System-Sicherheit bedeutet.

Stichwort-Liste

0.7.1 Black Hat 2009: Vincenzo Iozzo

Die etwas vage gehaltene Ankündigung des Vortrages von Vincenzo Iozzo für die Black Hat 2009 sorgte für diverse fehlgeleitete Spekulationen in den Nachrichten. Durch Nicht-Wissen, worum es wirklich gehen könnte, und die angekündigte Präsentation auf einer Konferenz für Angriffstechniken, schlossen viele Artikel schlagzeilen-trächtig auf eine neu entdeckte Sicherheitslücke in OS X.

Wenn man jedoch auf Gespenster-Märchen verzichtet und erfährt, worum es geht, dann stellt sich das Ganze als eine sehr interessante Technik dar, die man sowohl für gute als auch für böse Zwecke nutzen kann; genauso wie man ein Küchenmesser einsetzen kann, um einen Apfel zu zerlegen oder um das Meerschweinchen umzubringen, so hat auch diese Technik unterschiedliche Anwendungsmöglichkeiten, aber sie ist nicht von Natur aus einem dunklen Zweck geweiht.

Im Endeffekt macht diese Technik einem Angreifer das "Eindringen in", "Befallen" oder "Erobern von" OS X nicht leichter. Sie stellt keinen neuen Angriffsweg (die coolen Kids sagen "attack vector") dar. Sie kann allerdings dazu verwendet werden, wenn man bereits erfolgreich eingebrochen ist, also den Rechner schon erobert oder dem Benutzer einen Virus oder Trojaner untergeschoben hat, zusätzliche Programme aufzurufen und dabei weniger Spuren zu hinterlassen als durch normale Programm-Aufrufe.

Das beste Mittel gegen FUD ist Wissen, daher sehen wir uns an, worum es hier geht:

0.7.2 Starten von Binär-Dateien

Die Technik, die Vincenzo Iozzo entwickelt hat, ist eine Alternative zum normalen Programm-Aufruf über den dafür verfügbaren System-Befehl execve().

Der execve()-System-Aufruf ist der einzige Mechanismus des Betriebssystem-Kerns, der Benutzer-Programmen zur Verfügung steht, um ein anderes Programm aufzurufen. Das Programm liegt dabei als Datei vor.

Vergleiche dazu in dem Buch Mac OS X Internals von Amit Singh das Kapitel 7.5 The execve() System Call.

Vergleiche dazu auch man execve.

Dies ist der Quelltext im Kern von OS X, der execve() enthält.

Das auszuführende Programm ist eine Binärdatei in einem bestimmten Format. Bei Windows ist das PE, welches auf dem veraltetem COFF von UNIX basiert. Bei den meisten Unices und GNU/Linux ist es ELF und bei OS X ist es Mach-O.

0.7.3 Userland execve()

Userland bedeutet, daß man sich nicht im Kern, sondern im Benutzerbereich bewegt. Ein userland execve() kann also ein anderes Programm starten, ohne den sonst üblichen System-Aufruf.

Eine wichtige Besonderheit ist, daß userland execve() ein Programm starten kann, welches nur im Hauptspeicher liegt. Es kann aber auch wie das normale execve() Programme von der Platte starten.

Dadurch, daß man zum Starten des Programms keine Datei angeben muß, ist es möglich, ein Programm per Netzwerk in den Speicher zu laden und dann direkt dort auszuführen, ohne es auf der Platte speichern zu müssen.

Für Angreifer ist dies dann auch der interessanteste Aspekt, denn sie können, wenn sie bereits ein Programm auf dem System übernommen haben, weitere Programme nachladen, und dabei vermeiden, daß sie durch Speichern der nachgeladenen Programme auf Platte, viele Spuren hinterlassen.

Diese Technik, Programme ohne Systemaufruf direkt aus dem Hauptspeicher zu starten, gibt es in jeweils verschiedenen Varianten für UNIX, GNU/Linux und für Windows schon länger. Außer den beiden referenzierten Beispielen gibt es noch weitere.

Bei Windows ist der originale System-Aufruf natürlich nicht execve(), sondern CreateProcess().

Vincenzo Iozzo mußte nachbauen, wie ein ausführbares Programm nach dem Laden im Speicher abgelegt wird.

Ein Interview mit Vincenzo Iozzo über diese Technik.

Charly Miller analysiert die Technik von Vincenzo Iozzo.

Vincenzo Iozzo sagt zwar, daß es vorher nicht möglich war, komplette ausführbare Dateien in einen Prozeß einzuschleusen, aber das stimmt nicht ganz, denn mit Objective C läßt sich etwas Vergleichbares realisieren, etwa wie die System-Einstellungen als prominentestes Beispiel in OS X ihre Module dynamisch, also zur Laufzeit (allerdings von der Platte) nachladen, wenn die entsprechende Einstellung angeklickt wird.

Mit userland execve() kann also ein Programm A ein anderes Programm B ausführen, ohne daß Programm B als Datei auf der Festplatte (oder sonstwo im Dateisystem) vorliegen muß. Das ist technisch sehr interessant und wir dürfen auf seine Beispiel-Implementierung gespannt sein.

0.7.4 Grenzen für diese Technik

Nachdem nun bekannt ist, was man mit Implementierungen von userland execve(), beispielsweise der von Vincenzo Iozzo, erreichen kann, bleibt die Frage, was man damit nicht tun kann.

0.7.4.1 Keine Sicherheitslücke, kein Fehler

Wie Vincenzo Iozzo selbst sagt, wird seine Technik von den Medien verzerrt dargestellt als etwas, was sie nicht ist: Sie stellt kein Schadprogramm dar, aber sie kann von Schadprogrammen benutzt werden, um einige Aktivitäten auf dem Opfer-System zu verschleiern. Sie erleichtert keinen Einbruch, aber sie macht die Programm-Ausführung auf einem erfolgreich angegriffenen System einfacher.

Vincenzo Iozzo macht auf mich daher einen sehr sympathischen Eindruck, weil er im Gegensatz zu vielen selbsternannten Hackern erstens offenbar eine eigene gute innovative Programmier-Leistung erbracht hat, indem er die erste Version von userland execve() für OS X implementiert hat, und diese zweitens realistisch einschätzt und nicht den "Hack", wie das üblicherweise bei anderen Hackern passiert, als den nächsten Weltuntergang für OS X verkauft. Insofern Lob, Respekt und Anerkennung für Vincenzo von meiner Seite. Es gibt zu wenige Leute mit Charakter wie ihn auf diesem Gebiet.

Ein Betriebssystem stellt Programmen diverse komfortable Routinen zur Verfügung, um alltägliche Aufgaben zu lösen. Es wird aber kein Programm gezwungen, diese auch zu benutzen. Um ein anderes Programm aufzurufen, muß man daher nicht zwingend den bereitliegeneden execve() nutzen. Man kann sich auch mehr Mühe machen und dies und einiges mehr selbst programmieren, wie es bei den Implementierungen von userland execve() auf den verschiedenen Betriebssystemen der Fall ist. Diese Eigenkreation kann natürlich Extras bieten, wie beispielsweise das Schmankerl, daß man nicht auf eine Datei der Festplatte angewiesen ist, die das ausführbare Programme enthält, sondern auch von irgendwo anders her das Programm direkt in den Speicher laden kann. Das stellt übrigens keine Verletzung der UNIX-Regeln dar, denn ein Programm darf ja in seinem Adreßraum machen, was es mag. Und es darf auch weiteren Speicher anfordern. Daß es den nun für einen selbstgeschaffenen Prozeß benötigt, interessiert das System nicht.

0.7.4.2 Nicht ganz so heimlich

Vincenzo Iozzo behauptet auch nicht, daß seine Technik völlige Unsichtbarkeit garantiert. Wenn damit ein Programm wie beispielsweise Safari gestartet würde, dann hinterläßt dieses natürlich die üblichen Spuren auf der Platte, wie es das sonst auch tut. Führt man jedoch ein speziell angefertigtes Schadprogramm aus, dann wird dieses darauf achten, nichts auf der Platte zu verändern.

Auf jeden Fall kann man aber durch Überwachung des Netzverkehrs feststellen, was passiert, denn das typische Schad-Szenario sieht hier so aus, daß nach einer Programm-Übernahme diese Technik verwendet werden kann, um aus dem Netz weitere Schadprogramme in den Speicher zu laden und zu starten. Auch durch Überwachung des Adreßraums, also beim Nachsehen, welche Prozesse auf dem System laufen und wie sich ihre Speicherbelegung verändert, kann ein Angriff auffliegen, der sich dieser Technik bedient.

Es ist momentan noch nicht klar, ob man einen so gestarteten Prozeß im Aktivitätsmonitor-Programm oder mit top oder mit ps als Prozeß in der Liste sehen kann oder ob sich nur der Speicherplatz des Mutter-Programms vergrößert. Diese Information werde ich erst nach seinem Vortrag haben können.

Eine weitere Möglichkeit zur Verhinderung so eines Szenarios ist, daß man Programme in einem Sandkasten laufen läßt, den man so einstellt, daß Netzverkehr nicht erlaubt ist. Das ist allerdings nur hilfreich bei Programmen, die kein Netz benötigen.

Ein Angriff, der nötig ist, um diese Technik anwenden zu können, muß wenigstens ein Programm unter seine Kontrolle bringen. Und dieser Angriff hinterläßt natürlich wie bisher alle seine Spuren. Nur die anschließend mittels userland execve() nachgeladenen Programme können von dem festplattenlosen Programme-Laden profitieren. Schlagzeilen wie "Angriff ohne Spuren" sind daher falsch, denn der eigentliche Angriff hat weiterhin Spuren und nur der nachgeladene Teil hat weniger Spuren.

0.7.4.3 ASLR als Bodenwelle

ASLR, die möglichst zufällige Belegung von Speicherplatz durch Daten, Programme und Bibliotheken, soll es einem Angreifer erschweren, die Adresse seines Angriffsziels herauszufinden. Im Grunde ist es Verstecken-Spielen: Der Angreifer muß sein Opfer erst im Speicher finden, bevor er es tatsächlich angreifen kann.

Die Implementierungen von ASLR unterscheiden sich darin, was alles "versteckt" wird. In Leopard wurde beispielsweise Library Randomization eingeführt. Für spätere Versionen rechne ich damit, daß weitere Bereiche von OS X "zufällig" werden, da bei dieser Version hauptsächlich bezüglich Sicherheitsaspekten weiterentwickelt wird.

In der Praxis hilft ASLR hier jedoch nicht besonders viel. Das sieht man daran, daß es userland execve() oder vergleichbare Techniken nicht nur bereits für diverse andere Unices und GNU/Linux gibt, sondern auch für Windows. Für Windows gibt es sogar Meterpreter, ein Modul für das Metasploit Framework.

Offenbar stellt ASLR in der Praxis auf keinem der Betriebssysteme ein ernstes Hindernis für Techniken dieser Art dar. Und wenn man in Betracht zieht, daß ASLR eigentlich nur eine Form von "security by obscurity" ist, dann ist klar, warum es sich dabei nur um eine Unebenheit auf der Straße handelt. Man sollte sich davon nicht zuviel versprechen.

Eine Untersuchung der Universität Stanford kommt zu dem Schluß, daß ASLR mit 32 Bit Programmen ziemlich unnütz ist. Sie haben sogar ein Programm entwickelt, welches aus einem Exploit, der ohne ASLR einen Pufferüberlauf ausnutzen kann, einen Exploit macht, der mit ASLR funktionioniert.

Sie kommen zu dem Schluß, daß Randomisation zur Übersetzungszeit und Randomisation zur Laufzeit, selbst wenn man beide kombiniert, den Angriff nur für wenige Sekunden aufhalten kann. Die einzig vielversprechende Lösung sehen sie darin 64 Bit zu nutzen, weil damit ein brutales Durchprobieren nicht mehr praktikabel ist, um ASLR zu überwinden.

Dies bedeutet, daß ASLR auf 32 Bit Systemen mit 32 Bit Programmen nur der Werbung für das System dient, es jedoch keineswegs sicherer macht. Eine weitere Schlußfolgerung ist, daß Schnee-Leopard als System, welches die meisten Programme in 64 Bit mitbringt ein sichereres ASLR bietet als die immer noch am weitesten verbreiteten 32 Bit Versionen von Windows.

0.7.4.4 Userland execve() im Praxistest

Ich habe userland execve(), nachdem Vincenzo Iozzo es veröffentlicht hatte, ausprobiert: Unter 10.5 funktioniert es. Es ist zur Laufzeit zu erkennen, wenn man die Nutzung des virtuellen Speichers des Prozesses überprüft, beipsielsweise mit vmmap. In den üblichen Werkzeugen (top, ps) taucht kein weiterer Prozeß auf. Der Grund ist, daß das nachgeladene Programm im Speicher des Opfers läuft und auch von diesem gestartet wurde, ohne das System zu nutzen. Die Anzeige ist also korrekt. Das eingeschleuste Programm taucht jedoch in der Benutzungsoberfläche auf, sofern es selbst eine hat. Wurde es bereits vom Benutzer vorher selbst gestartet, dann erscheint es nach dem Einschleusen ein zweites Mal in der Obefläche, auch im Dock und im Programm-Umschalter.

Wenn man weiß, worauf zu achten ist, erkennt man die Aktivität auch mit einem Netzwerk-Analyse-Werkezeug wie Wireshark.

Es gibt jedoch ein paar Praxisprobleme: userland execve() kommt anscheinend mit Universal-Binaries nicht klar: Man kann zum Beispiel reine 32-Bit-Intel-Binaries in den Opfer-Prozeß nachladen, muß die Version also gegebenenfalls aus dem Universal-Binary vorher erst herauskopieren.

Außerdem funktioniert es nicht mehr mit 10.6: Der Angriff scheitert mit einem Segmentation fault des Opferprogramms, sobald das nachzuladende Programm dort eingeschleust und gestartet werden soll. Vincenzo sagte mir, als ich ihn darauf ansprach, daß er es selbst noch nicht auf 10.6 probiert habe und sein Programm möglicherweise nochmal dafür angepaßt werden müßte.

Ein anderes Problem ist, daß das nachgeladene und im Opferprogramm dann gestartete Programm eventuell bestimmte Ressourcen auf der Platte sucht und zwar relativ zu der Stelle, an der das Opferprogramm läuft. Programme auf OS X sind nicht das was man im Finder sieht: Es sind tatsächlich Verzeichnisse, die die ausführbare Datei und zugehörige private Ressourcen enthalten. Die ausführbare Datei findet diese ihre privaten Ressourcen jedoch nicht mehr, wenn sie in ein fremdes Programm eingeschleust wurde. Daher sind nur sehr einfache Programme, die keine privaten Ressourcen verwenden, einschleusbar. In seiner Vorführung umging Vincenzo das Problem, indem er das Opferprogramm von einem anderen Pfad aus aufrief. Darauf hat man jedoch im realen Fall keinen Einfluß.

Valid XHTML 1.0!

Besucherzähler


Latest Update: 11. September 2015 at 19:51h (german time)
Link: realmacmark.de/osx_userland-execve.php