Zero-Day-Exploits zuvorkommen mit American Fuzzy Lop
Mar 1, 2017AFLFuzzingExploits
Spricht man von Speicherzugriffsfehlern (memory fault) von Programmen, so handelt es sich dabei meistens um Pufferüberläufe (buffer overflow/overrun), die in verschiedenen Typen vorkommen. Bei einem Stack Overflow1 – wie er in einem klassischen Artikel von dem Hacker Aleph One das erste Mal ausführlich beschrieben worden ist2 – oder einem Heap Overflow3 schreibt ein Programm bei der Ausführung unerwünscht über vorgesehen Datenbereiche hinaus in den Arbeitsspeicher, ohne die Daten ausreichend auf ihre Länge hin zu überprüfen. “Pufferüberlauf” wird oft auch als Sammelbegriff benutzt für verschiedene verwandte Phänomene wie den arithmetischen Überlauf (integer overflow). Mit in dieselbe Kategorie gehören aber auch Speicherunterläufe (buffer undeflow/underrun), und Lesefehler (out-of-bounds-read bzw. read overflow). Andere Speicherfehler sind zum Beispiel hängende Zeiger wie bei use-after-free-Problemen. Es handelt sich bei diesen Speicherfehlern um potentielle Sicherheitslecks, die in vielen Fällen geschickt ausgenutzt werden können, und die oftmals eine schwerwiegende Bedrohung für die Sicherheit des gesamten Systems darstellen – der Pufferüberlauf belegt Platz 3 der Liste “Top 25 Most Dangerous Software Errors” von MITRE4. Beim gravierenden “Heartbleed”-Bug in OpenSSL (CVE-2014-0160)5, bei dem man relativ einfach ein Stück Speicher aus einem Zielsystem mit im Glücks- bzw. Unglückfall brisanten Daten auslesen kann6, handelt es sich zum Beispiel um einen “out-of-bounds-read”-Fehler im TLS-Handshake dieser Bibliothek7. Administratoren müssen ein wachsames Auge darauf haben, ob von der eingesetzten Software solche Sicherheitsmängel bekannt werden, und sich um eine zeitnahe Einspielung von Patches bzw. um Updates kümmern. Bemerkung am Rande: das ist leider im erschreckenden Umfang oftmals aber nicht der Fall8. Die Ursache für Speicherfehler liegt in Nachlässigkeiten im Programmcode bzw. an einer an bestimmten Stellen unzureichenden Programmierung. Oftmals handelt es sich dabei aber eher um subtile Mängel, die vor der Veröffentlichung der Software – und auch danach – meist nicht ohne weiteres erkennbar sind, und die meist durch die Eingabe von nicht vorgesehenen oder korrumpierten Daten trickreich hervorgerufen werden (oft sind Parser von komplexen Multimedia-Formaten betroffen): das sind Programm-Hacks. Manche Pufferüberläufe haben keinen besonderen Effekt, bei anderen kann es aber durch Speicherzugriffsverletzungen (segmentation fault, SIGSEV) und zu einem Absturz des betroffenen Programmes bzw. Prozesses kommen. Es droht bei Speicherfehlern aber auch die Veränderung und der Verlust von Daten, und die Beschädigung von Datenstrukturen und Laufzeitumgebungen. Die Problematik betrifft vor allem die Sprachen C und C++, die als eine Art effiziente “High Level-Assembler” fungieren und keinen eingebauten Speicherschutz besitzen. Das ist ein Mangel dem unter anderem die relative neue Programmiersprache Rust der Mozilla Foundation mit eingebautem Speichermanagement begegnen will.
Software-Bugs der hier beschriebenen Kategorie finden sich oft wieder als Bestandteil von “Exploits” (Methoden zur Ausnutzung von Sicherheitslücken)9, wenn sie zum Angriff auf Computersysteme eingesetzt werden bzw. benutzt werden können10. Angreifer aus dem Internet haben dabei immer dieselben Interessen: an Daten und Informationen zu gelangen oder sie zu manipulieren, um Sabotage und das Blockieren von Systemen (denial-of-service), oder die Übernahme und Kontrolle davon, indem man an Root-Rechte gelangt (privilege escalation). Wenn man weiß wie und bei welchen Programmversionen, dann können Speicherfehler in Programmen bewusst hervorgerufen werden um für verschiedene vom Systembetreiber unerwünschte Dinge ausgenutzt zu werden. Pufferüberläufe zum Beispiel können benutzt werden um Speicher interne Rücksprungadressen zu überschreiben und so eingeschleusten Schadcode zur Ausführung zu bringen (arbitrary code execution). Es kann damit auch die Rechteverwaltung ausgehebelt werden um an Root-Rechte zu gelangen. Oftmals werden durch Speicherfehler hervorgerufene Programmcrashs in mehrstufigen, teilweise schwierig nachvollziehbaren Angriffen eingesetzt, bei denen unter anderem auch gerne mit SUID-Bits gearbeitet wird. So existiert ein ganzes Arsenal von Brechstangen bzw. Spezialschlüsseln, die bei älteren, nicht aktualisierten oder entsprechend gepatchten Programmversionen auf Zielrechnern schnell und erfolgreich eingesetzt werden können. Tatsächlich genügt eventuell sogar auch einfach ein aus einem Email-Anhang geöffnetes, speziell präpariertes Bild um wegen einer Codeschwäche beim Bildbetrachter einen unberechtigten Zugang auf das eigene System zu ermöglichen – man muss sich nur mal die Anhänge im eigenen Spam-Ordner mal ein bisschen genauer ansehen, um ein Beispiel zu finden. Sicherheitslecks wie etwa von Webbrowsern – Multimedia-Extensions wie der Flashplayer sind dabei äußerst beliebt – finden sich kurz nach ihrer Bekanntmachung meistens auch direkt wieder in den sogenannten “Exploit-Kits”. Dabei handelt es sich um relativ einfach anzuwendende, dreckige Toolkits aus der Cyberkriminalität, mit denen zum Beispiel die Rechner der Besucher von präparierten Webseiten mit Schadsoftware wie Ransomware infiziert werden können11. Als “Zero-Day-Exploits” werden offiziell nicht bekannt gewordene Angriffsmethoden bzw. Sicherheitslücken in Software bezeichnet, die dementsprechend auch nicht von dem/den Entwickler(n) geschlossen werden konnten. Das sind geheim gehaltene Entdeckungen von im Verborgenen bleibenden “black hat”-Hackern, die bekannter Maßen auch von Geheimdiensten und von Firmen, die Spionagesoftware anbieten – je nach ihrem Schwere- bzw. Einschlägigkeitsgrad – manchmal zu stattlichen Summen angekauft werden12. Die Frage, wie Softwarentwickler (die daran interessiert sind, robuste Programme zu vertreiben) oder IT-Sicherheitsfachleute (die betreute Systeme einbruchssicher haben wollen) dem Exploit-Wesen wirksam begegnen wollen, ist recht einfach beantwortet: diese Sicherheitslücken am besten selber aufspüren, bevor es andere tun – oder längst getan haben. Und es gibt dafür zum Glück mittlerweile ein sehr wirksames Mittel: das Fuzzy-Testing oder Fuzzing von Software.
Wie bereits geschrieben handelt es sich bei Sicherheitslecks wie Quellen für Pufferüberläufe meist um subtile Codemängel jenseits des normalen Funktionierens von Programmen, und so spielen allzu unbedachtes oder schlampiges Programmieren auch nur eine untergeordnete Rolle für ihre Entstehung13. Meistens lassen sich sicherheitskritische Mängel auch bei wiederholter Codedurchsicht nur sehr schwierig herauslesen, und oftmals handelt es sich dabei um reine Zufallsfunde – der Heartbleed-Fehler befand sich ganze 2 Jahre im offenen und von jedermann einsehbaren Code von OpenSSL, bevor er von “white hat”-Leuten gefunden und gemeldet wurde, und geschlossen werden konnte. Statische Analysemethoden eignen sich dementsprechend auch nur bedingt für das automatisierte Auffinden von hintergründigen Sicherheitslecks, denn statische Analyzer parsen den Quellcode im Hinblick auf bestimmte Richtlinien, und nicht in Bezug auf alle Anwendungsfälle, die der Programmierer nicht bedacht hat. Auch abgesicherte Entwicklungsmethoden wie die Testgetriebene Entwicklung (TDD)14 bringen keinen entscheidenden Vorteil bei der Bekämpfung von subtilen Sicherheitslecks, weil hierbei vor allem immer der beabsichtigte bzw. vorgesehene Programmablauf im Sinne der Spezifikation (der “happy path”) im Mittelpunkt steht. Anders ist es beim Fuzzing, das im Jahr 1989 von Bart Miller entwickelt worden ist, und das eine sehr effektive dynamische Testmethode (das Programm wird dabei ausgeführt) für das Auffinden von Schwachstellen und Robustheitsmängeln in Programmen ist15. Ein Fuzzer “bombardiert” die zu testende Software einfach immer weiter mit nach verschiedenen Strategien – wie zum Beispiel Bitflips – erzeugten Mutationen von Eingabedateien mit dem Ziel, irgendwann eventuell auf eine bestehende Codeschwäche zu treffen und das Programm mit irgendwas zum Hängen oder zum Absturz zu bringen16. Dabei werden schon nach kurzer Zeit Millionen von Varianten durchprobiert. Es werden durch diese Methode gerade auch Randfälle und unzulässige Eingaben erzeugt, und es handelt sich dabei mehr oder weniger um zufällige bzw. unvorhersehbare Testfälle17 – das ist hierbei der entscheidende Vorteil. Fuzzing stellt sich als äußerst effektiv heraus und kommt mittlerweile vielfältig zum Einsatz, der Fuzzer Trinity zum Beispiel wurde erfolgreich bei der Kernelentwicklung eingesetzt, und Heartbleed konnte mit dieser Methode von einem finnischen Sicherheitsunternehmen entdeckt werden18.
Bei American Fuzzy Lop (AFL, der Name stammt von einer flauschigen Kaninchenrasse) von Michał Zalewski bei Google handelt es sich um einen solchen Fuzzer19, der unkompliziert für das Durchtesten von beliebigen Programmen und Bibliotheken (dafür muss man ggf. eine kleine Anwendung aufsetzen) auf einem Arbeitsrechner eingesetzt werden kann20. Das Fuzzen beginnt man am besten mit einer gültigen Eingabedatei, also etwa einem PDF-Dokument oder eine JPG-Datei (ein Satz von extra kleinen Testdateien wird mitgeliefert), und der Fuzzer rattert los und arbeitet die eingebauten Mutationsstrategien durch. Es kann durchaus einige Tage dauern, bis ein Hänger oder ein Crash bei dem getesteten Programm registriert wird, und man sollte dem Fuzzer immer großzügig Zeit lassen. Bei AFL handelt es sich um einen “white box”-Fuzzer, und der entscheidende Vorteil im Gegensatz zu vergleichbaren Produkten wie Zzuf ist, dass das Werkzeug das zu testende Programm mit einer speziellen “Ausstattung” (instrumentation) versehen kann21. Dafür muss der Code des Testobjektes für das Testen mit AFL vorher speziell kompiliert werden, und Wrapper für GCC und Clang dafür werden mitgeliefert. Abzweigungen im Codepfad (execution path) werden dabei mit Markern ausgestattet, die AFL beim Fuzzen abfragen kann22. Dabei kann festgestellt werden, ob der innere Zustand des getesteten Programmes sich verändert hat, und ob eine neue Testeingabe tiefer in den Codepfad eindringen konnte als die vorherigen. Das bringt einen entscheidenden Vorteil: anstatt dumpf alle möglichen Testfälle “von vorne bis hinten” durchzuarbeiten (Stichwort: brute force) hat der Fuzzer sozusagen eine eingebaute Intelligenz um gute effektive Testeingaben zu finden, für die auch evolutionäre Algorithmen zum Einsatz kommen. Es ist zum Beispiel sehr faszinierend, das mit diesen Mitteln beim Testen eines JPEG-Parsers irgendwann konforme Grafikdateien durch Mutation erzeugt werden, auch wenn das Fuzzen experimentell mit einer Textdatei begonnen wird, die lediglich das Wort “hello” enthält23. Der Fuzzer weiß nach einiger Zeit, wie er hierbei weiterkommt, denn der getestete Parser nimmt überhaupt nur JPEG-konforme Eingaben an. Das “black box”-Fuzzing für Fälle, in denen kein Quellcode sondern nur die Binärdatei eines Testobjektes zur Verfügung steht, ist mit AFL aber auch möglich indem der Emulator Qemu als Testumgebung eingesetzt wird, und die benötigten Marker können dann zur Laufzeit eingefügt werden. Fuzzen ganz ohne Instrumentierung geht aber natürlich auch, obwohl der Fuzzer damit unter seinen Möglichkeiten bleibt.
Die lange und saftige Liste der Jagdtrophäen von AFL spricht für sich, und tatsächlich konnten mit dem Fuzzer bisher bereits viele Dutzend, teilweise äußerst brisante Sicherheitslücken in weit verbreiteter Software aufgespürt werden. Kurz nach der Veröffentlichung des gravierenden “Bashdoor” bzw. “Shellshock”-Bugs in der GNU Bash (), mit dem beliebiger Code zur Ausführung gebracht werden kann24 – es handelt sich dabei nach Heartbleed um den zweiten sicherheitstechnischen “Super-GAU” von 2014 – konnte Zalewski mit seinem Werkzeug zwei weitere, ähnliche Sicherheitslücken aus der Bash herauskitzeln, die heute mit zum Shellshock als eine ganze Bug-Familie gerechnet werden (). In 2015 hat AFL wieder eine wichtige Rolle gespielt, indem damit einige der üblen Sicherheitslecks in der Multimedia-Bibliothek “Stagefright” von Android-Mobiltelefonen bis 5.1 aufgedeckt werden konnten (). Die Codemängel und die daraus entstehenden Angriffsvektoren25 sind auf der Black Hat-Konferenz desselben Jahres ausführlich vorgestellt worden26. Das Sicherheitsproblem ist so gravierend gewesen27, dass die Deutsche Telekom sich sogar dazu entschlossen hatte, den MMS-Empfang in ihrem Mobilfunknetz erstmal besser komplett zu deaktivieren. Um die 950 Millionen Mobiltelefone weltweit waren von dieser Bug-Familie betroffen – es handelt sich dabei zweifellos um den “Super-GAU” von 2015. Mittlerweile ist außerdem nachgewiesen worden, dass AFL natürlich auch Heartbleed finden kann bzw. auch hätte finden können28. Das sind aber natürlich nur die “großen”, spektakulären Fälle29, die teilweise auch sogar einer breiteren Öffentlichkeit bekannt geworden sind, und dadurch stark für diesen Fuzzer werben. Das aber nur ein kleiner Bruchteil der wichtigen Arbeit im Bereich IT-Sicherheit, die mit AFL bisher geleistet werden konnte und es ist zu vielen Bugfixes in wichtigen Bibliotheken und Services gekommen wie zum Beispiel OpenSSL (CVE-2015-0208, 0288 u.a.) und bind9 (CVE-2015-5477).
- Oliver Müller: “Überläufer – Systemeinbruch via Stack-Overflow”. In: iX 02/2007, S. 100-105 [return]
- Aleph One: “Smashing the stack for fun and profit”. In: Phrack Vol. 7, Issue 49. Abgerufen am 26.2.2017 [return]
- Felix Lindner: “*. Artikel auf Heise Security vom 28.4.2006 [return]
- http://cwe.mitre.org/top25/#CWE-120: CWE-120: Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’) [return]
- Klaus Schmeh: “Herzfehler – Der Heartbleed-Bug in OpenSSL”. In: iX 05/2014, S. 80-81 [return]
- Mark Vogelsberger, Mathias Huber: “Blutendes Herz ‒ Heartbleed-Bug in OpenSSL”. In: Linux-Magazin 07/2014, S. 88–90 [return]
- Uli Ries: “SSL-GAU lässt Server bluten – kritischer Fehler bei der Verschlüsselung”. In: C’t Nr. 10/2014, S. 16-17 [return]
- Hauke Gierow: “Weiterhin rund 200.000 Systeme für Heartbleed anfällig”. Beitrag auf golem.de vom 23.1.2017 [return]
- Manu Carus: “Deep Dive – Die Entwicklung eines Exploit”. In. iX 02/2016, S. 122-128 [return]
- Christoph Haas: “Angebohrt – Exploit-Techniken am Beispiel von Vulnserver”. In: iX 11/2012, S. 108-114 [return]
- Olivia von Westernhagen: “Einbruch mit Komfort – Exploit-Kits als Basis moderner Cyber-Crime”. In: C’t Nr. 18/2015, S. 78-83 [return]
- Uli Ries: “Digitaler Waffenhandel – Das geheime Geschäft mit Zero-Day-Exploits”. In: C’t Nr. 18/2015, S. 87 [return]
- Mathias Huber: “Auf Fehlersuche – Sicherheitsschwächen in Software finden”. In: Linux-Magazin 08/2014, S. 40-42 [return]
- Gunnar Wrobel: “Präziser Antrieb – Testgetriebene Software-Entwicklung”. In: Linux-Magazin 08/2012, S. 32-37 [return]
- Dirk Fox: “Fuzzing”. In: Datenschutz und Datensicherheit (DuD) Nr. 30,12/2006, S. 798 [return]
- Michael Sutton, Adam Greene, Pedram Amini: Fuzzing – Brute Force Vunerability Discovery. Addison-Wesley 2007. ISBN 0-321-44611-9 [return]
- Maximilian Kögel, Jonas Helming, Julian Sommerfeldt: “”. Artikel auf Heise Developer vom 19.10.2016 [return]
- Antti Karjalainen: “”. Vortrag auf der Sec-T 2014 [return]
- Hanno Böck: “Auf Fehlersuche mit American Fuzzy Lop”. Artikel auf golem.de vom 7.7.2015 [return]
- Tom Viner: “”. Vortrag auf der EuroPython 2015 vom 8.8.2015 [return]
- Richard Johnson: “”. Vortrag auf der B-Sides 2015 Knoxville [return]
- Jonathan (jn): “afl-fuzz”. Vortrag im Chaos Computer Club Aachen am 6.5.2015 [return]
- “Pulling JPEGs out of thin air”. Beitrag auf Zalewskis Blog vom 7.11.2014 [return]
- Christoph Dreher: “Schwerenot – Sicherheitslücke auf Linux- und Unix-Systemen”. In: iX 11/2014, S. 18 [return]
- Hanno Böck: “Elf Wege, ein Android-System zu übernehmen”. Artikel auf golem.de vom 6.8.2015 [return]
- Joshua Drake: “”. Vortrag auf der Black Hat 2015 vom 7.8.2015 [return]
- Thomas Gronenwald, Alexander Schäfer: “Löchriger Käse”. In: IT-Administrator 09/2015, S. 64-65 [return]
- Hanno Böck: “Wie man Heartbleed hätte finden können”. Artikel auf golem.de vom 7.4.2015 [return]
- “Black-Hat-Konferenz: Experten warnen vor immer gravierenderen Sicherheitslücken”. In: Computerwoche 34-35/2015, S. 12 [return]