Über unsMediaKontaktImpressum
Dr. Khaled Yakdan 01. März 2022

Fuzzing als Security-Testing-Methode

Unter Security-Forschern ist man sich weitestgehend einig: Fuzz-Testing ist derzeit das effektivste Testverfahren, um Sicherheitslücken in Software aufzudecken. Tech-Riesen wie Google setzen deshalb schon länger auf die Technologie. Alleine im Chrome-Browser hat Google seit 2016 bereits über 29.000 Bugs mithilfe von Fuzz-Testing gefunden und nach eigenen Angaben auch über 35.000 Bugs in 550 weiteren Open-Source-Anwendungen [1]. Was macht Fuzz-Testing als Security-Testing-Methode so effektiv? Wie wird Fuzzing in der Praxis eingesetzt? Und was können wir von dieser Technologie noch erwarten?

Was ist Fuzz-Testing?

Fuzz-Testing (oder auch "Fuzzing") ist eine dynamische Testmethode, die zum Auffinden von Bugs und Sicherheitsproblemen in Software eingesetzt wird. Bei einem Fuzz-Test wird ein Programm mit ungültigen, unerwarteten oder zufälligen Eingaben ausgeführt, mit dem Ziel, die Anwendung zum Absturz zu bringen [2].

Moderne Fuzzing-Lösungen analysieren dabei die Struktur des Codes, den sie testen, und erzeugen dabei tausende automatisierte Testfälle pro Sekunde. Der Prozess ist darauf ausgerichtet, mit den generierten Eingaben möglichst viele neue Programmzustände (States) zu erreichen. Zudem markiert der Fuzzer auch die einzelnen Pfade, die von diesen Eingaben durchlaufen werden und erhält somit detailliertes Feedback über die Testabdeckung, die bei der Ausführung des Quellcodes erreicht werden. Auf diese Weise lernen Fuzzer mit jeder Iteration mehr über die Struktur der erwarteten Eingaben.

Sobald ein Fuzzer eine Eingabe, die zu einem Crash führt, gefunden hat oder einen neuen State erreicht, verwendet er Mutationsalgorithmen, um weitere Eingaben zu generieren, die den Crash oder den State mit hoher Wahrscheinlichkeit reproduzieren. Da moderne Fuzzer durch dieses Verfahren auch zufällige und ungültige Eingaben testen, können sie auch unwahrscheinliche oder unerwartete Randfälle abdecken, die von anderen Testansätzen leicht übersehen werden.

Fuzzing findet log4j RCEs

Fuzzing kann automatisch erkennen, ob eine Anwendung Remote Code Executions und oder andere Schwachstellen enthält, sofern die Anwendung für Fuzzing instrumentiert wurde [3]. Entsprechende Bug-Detektoren für log4j und ähnliche Remote Code Executions sind bereits in verschiedenen Open-Source-Fuzzern, wie Jazzer oder Googles Open-Source Fuzzing Framework OSS-Fuzz verfügbar [4].

Frühe Fuzzing-Ansätze: 60 Jahre Grundlagenforschung

Die ersten Versuche, Software mit zufälligen Eingaben zu testen, stammen bereits aus den 50er Jahren, als Programme noch mit Lochkarten betrieben wurden. Damals fütterte man Programme mit Eingaben von zufälligen Lochkarten und wartete ab, ob das Programm unerwartetes oder unerwünschtes Verhalten aufzeigt. Diese Idee wurde in den 80er Jahren dann erneut aufgegriffen, als Joe Duran und Simeon Ntafos nachweisen konnten, dass solche randomisierten Testprogramme tatsächlich eine effektive und kostengünstige Alternative zu manuellen Testverfahren darstellen. Aus dieser Zeit (1988) stammt auch der Begriff Fuzz-Testing, der von Barton Miller geprägt wurde. Diese frühen Fuzzing-Ansätze betrachteten Anwendungen jedoch als reine Blackbox und wären aus heutiger Perspektive extrem zeitintensiv. Zudem konnten mit diesem Verfahren nur solche Bugs gefunden werden, die auch zum Absturz einer Anwendung führen. Mithilfe von speziellen Bug-Detektoren ist es jedoch heute auch möglich, andere Bugs zu erkennen, die nicht zwangsläufig zu einem Absturz führen.

Der Durchbruch: Feedback-Based Fuzzing

Der große Durchbruch der Technologie wurde erzielt, als es Wissenschaftler:innen gelang, Code zu instrumentieren, um dem Fuzzer zusätzliche Informationen und Feedback über die Anwendung zu geben. Bei der Instrumentierung werden während der Ausführung der Anwendung an klar definierten Stellen spezielle Fuzzing-Marker in die kompilierte Anwendung eingesetzt. Zum Beispiel an allen Start- und Endpunkt von allen if-Funktionen in einer Anwendung. Auf diese Weise können Fuzzer auch nachvollziehen, welche Pfade und Programmzustände (States) von verschiedenen Eingaben erreicht werden. Mithilfe von maschinellem Lernen lassen sich Fuzzer zudem darauf trainieren, eine möglichst hohe Testabdeckung zu erreichen.

Ein weiterer Vorteil der Instrumentierung besteht auch darin, dass Fuzzer üblicherweise Startdaten benötigen, aus denen sie gültige Eingaben und Zufallsmutationen generieren. Zumindest beschleunigt dies den Fuzzing-Prozess, da diese Eingaben dem Fuzzer Anhaltspunkte geben, wie er seine Eingaben am besten mutieren kann. Für diese Startdaten wurde in der Vergangenheit deshalb meist auf Test-Inputs von Unit-Tests zurückgegriffen, die manuell konfiguriert wurden, was jedoch ziemlich zeitaufwändig sein kann. Doch durch die verbesserte Instrumentierung können Fuzzer nun die notwendigen Informationen automatisch aus dem Quellcode der zu testenden Software entnehmen, was die Effizienz und Effektivität von Fuzzing deutlich verbessert und die Notwendigkeit von Unit-Test-Daten beseitigt.

Microsoft und Google treiben Industrieforschung voran

Tech-Konzerne wie Microsoft und Google haben Fuzzing-Technologien bereits früh aufgegriffen, um ihre eigenen Systeme damit zu testen. Google veröffentlichte 2012 im Rahmen einer größer angelegten Open-Source-Strategie mit ClusterFuzz die erste cloud-basierte Fuzzing-Infrastruktur [6]. Seitdem entstanden auch zahlreiche Open-Source-Tools (wie zum Beispiel AFL, libFuzzer, HonggFuzz und OSS-Fuzz), die es immer mehr Menschen ermöglichen, Fuzzing-Technologien zu nutzen. Zu diesem Zeitpunkt zeichnete sich bereits ab, dass sich Fuzzing als Best Practice im Security-Testing durchsetzt. Doch ein großes Problem, das zu dieser Zeit noch im Raum stand, war die Usability von Fuzz-Testing. Open-Source-Tools wie AFL und libFuzzer waren in erster Linie von Security-Experten für Security-Experten entwickelt worden und für sehr spezifische Anwendungsfelder gedacht. Normale Entwickler konnten damit zunächst wenig anfangen.

Fuzzing-Technologien erreichen Marktreife

Doch ab ca. 2016 erreichte die Technologie Marktreife. Verschiedene kommerzielle Anbieter entwickeln seitdem Fuzzing- Lösungen, die sich an Security-Experten und Entwickler richten. Diese Security-Testing-Plattformen lösen unter anderem Probleme, die im Unternehmenskontext und der Arbeit in größeren Entwicklungsteams relevant werden, wie zum Beispiel Web-API-Fuzzing oder OWASP-Schwachstellenerkennung. Sie unterstützen Entwickler zudem bei der Instrumentierung und beim Aufsetzen von Fuzz-Tests und verfügen auch über hilfreiche Reporting-Dashboards, sowie CI/CD- und Dev-Tool-Integrationen, die zur Produktivität im Entwicklungsprozess beitragen (DevSecOps).

Immer mehr Industriestandards setzen Fuzzing voraus

Die Technologie wird auch in immer mehr Industriestandards aufgegriffen. Denn in sicherheitsrelevanten Bereichen sind Softwarehersteller dazu verpflichtet, automatisierte Software- und Sicherheitstests durchzuführen. Einige Industriestandards und ISO-Normen empfehlen daher schon heute, Fuzz-Testing in den Entwicklungsprozess zu integrieren [7]. Insbesondere dort, wo die Qualität und Sicherheit von Software über Leib und Leben entscheidet.  

Ein gutes Beispiel dafür sind ISO/SAE 21434 und UNECE WP.29, die sich mit der Sicherheit von Automobil-Software befassen [8]. Doch auch in weiteren Branchen, wie zum Beispiel der Luftfahrt, dem Energiesektor, dem Finanzsektor und dem Gesundheitswesen, ist Fuzzing als modernes Testverfahren weit verbreitet.

Was macht Fuzzing als Security-Testing-Methode so effektiv?

Als eine Art "entwicklungsbegleitendes Pentesting", ist Fuzzing eine hilfreiche Ergänzung zu klassischen Security-Audits, weil es die Entwickler und Security-Experten in vielerlei Hinsicht entlastet.

Fuzzing ermöglicht effizientes Debugging ohne False Positives

Mit Unit-Tests, oder statischer Code Analyse, kann Debugging hin und wieder eine zeitintensive und nervenaufreibende Tätigkeit sein. Denn Softwarefehler müssen manuell lokalisiert und nachvollzogen werden, bevor die Schwachstellen behoben werden können. Bei dynamischen Security Testing Ansätzen, wie Fuzzing wird der Code jedoch tatsächlich ausgeführt und mit realen Eingaben getestet. Das bedeutet auch, dass zu jedem Bug Report ein Input als Nachweis mitgeliefert wird, der letztendlich zum Absturz geführt hat. Somit liefert Fuzzing Entwicklern und Security Experten auch den notwendigen Anwendungskontext, um Fehler möglichst schnell nachzuvollziehen und zu beheben.

Fuzzing liefert aussagekräftige Bug Reports mit Angaben zur Testabdeckung

Fuzz-Tests, die auf dem Source-Code durchgeführt werden, enthalten wichtige Angaben zur Codeabdeckung. Zum Beispiel zur Zeilen- oder Pfadabdeckung, die bei der Ausführung der Eingaben erreicht wurde. Diese Angaben zur Testabdeckung sind wichtige Metriken für Sicherheitstests, da sie dabei helfen, einzuschätzen, wie hoch das verbleibende Restrisiko ist, kritische Sicherheitslücken zu übersehen. Sie ermöglicht es Entwicklern, auch Aussagen darüber zu treffen, welche Teile des Codes von den Testeingaben bereits durchlaufen wurden. Diese Informationen helfen bei der Interpretation der Testergebnisse und liefern aussagekräftige Testberichte.

CI/CD-Integration ermöglicht kontinuierliches Security-Testing

Viele Fuzz-Testing-Tools lassen sich problemlos in CI/CD-Tools wie Jenkins oder Github Actions integrieren. Entwickler können somit mit jedem Pull Request einen automatisierten Sicherheitstest durchführen und Softwarefehler schon möglichst früh im Entwicklungsprozess aufzudecken.

Wie Fuzzing einen Ethereum-Shutdown verhindern konnte

Fuzz-Testing findet Bugs, die andere Testverfahren nicht aufdecken können. So konnte im Source-Code des Ethereum-Netzwerks nur wenige Wochen, nachdem dort Fuzz-Testing in die CI/CD integriert wurde, eine schwerwiegende DoS-Sicherheitslücke behoben werden. In den falschen Händen hätte diese Schwachstelle (CVE-2020-28362) dazu führen können, dass das gesamte Ethereum-Netzwerk heruntergefahren würde [9].

Best Practice: Wie wird Fuzzing in der Praxis eingesetzt?

Fuzzing ist am effektivsten, wenn kontinuierlich getestet wird. Deshalb bietet es sich an, Fuzzing in die CI/CD zu integrieren. Dies ermöglicht kurze Feedback-Zyklen und macht es Entwicklern möglich, Sicherheitslücken schnell zu beheben, bevor sie zu einem Problem werden.

Doch wenn man Fuzz-Testing in die CI/CD integriert, sollte man als Entwickler darauf achten, die Pipeline nicht zu lange zu blockieren. Denn Fuzzing kann unter Umständen sehr lange dauern. Dieses Problem kann man lösen, indem man feste Zeiträume definiert, in denen "gefuzzt" werden soll. Zum Beispiel nachts, zwischen 22:00 und 06:00 Uhr. Oder, in dem man regelmäßig Regressionstests durchführt. Der Fuzzer kann auch den Korpus und die Crash-Inputs aus vergangenen Testdurchläufen übernehmen, sodass man nicht bei jedem Test wieder bei null anfangen muss.

Wenn man in größeren Entwicklungs-Teams zusammenarbeitet, kann es zudem sinnvoll sein, Fuzzing-Tools in Code-Hosting-Systeme wie Gitlab oder GitHub zu integrieren. Dies erleichtert die Kommunikation im Team und weist Entwickler auch darauf hin, falls bei einem Pull Request ein Problem gefunden wurde. Einige kommerzielle Fuzzing-Lösungen bieten solche Integrationen sowie hilfreiche Schnittstellen zu Issue-Tracking-Systemen wie Jira und Jenkins an. 

Ausblick: Was können wir von Fuzzing noch erwarten?

Fuzz-Testing etabliert sich als neuer Standard im Security-Testing. Immer mehr Unternehmen, wie zum Beispiel die Deutsche Telekom, Bosch oder Volkswagen, setzen heute schon Fuzzing-Technologien ein. Doch ein Blick auf aktuelle Publikationen und Entwicklungen im Bereich Fuzzing und Security-Testing zeigt, dass in diesem Feld immer noch eine Menge Bewegung stattfindet [10]. Drei große Trends sind dabei zu erkennen:

  1. Fuzzing wird für immer mehr Anwendungskontexte interessant: Lange Zeit war Fuzzing überhaupt nur für sehr spezifische Anwendungsfelder und für wenige Programmiersprachen, wie C/C++ und Go, einsetzbar. Der Language-Support wird von der Entwickler-Community jedoch fortlaufend ausgebaut, sodass heute bereits eine ganze Reihe guter Open-Source-Fuzzer existieren, mit denen sich auch Anwendungen in Java, Python, Kotlin und Rust fuzzen lassen. Mit der Zeit werden sicher auch weitere Programmiersprachen und Anwendungsmöglichkeiten erschlossen. Gleichzeitig wird auch die Instrumentierung von Fuzzing immer weiter verbessert und für immer mehr Frameworks automatisiert (z. B. Spring Boot).
  2. Fuzzing wird effizienter und effektiver: Mithilfe von Bug-Detektoren ist es schon heute möglich, Anwendungen mit Fuzzing – schnell und gezielt – nach spezifischen Bug-Klassen zu scannen. Für log4j, SQL-Injections, Memory Corruptions und viele weitere Schwachstellen sind solche Bug-Detektoren bereits verfügbar [11]. Doch es ist auch davon auszugehen, dass mit der Zeit immer mehr Bug-Detektoren open-sourced werden. Insbesondere im Bereich OWASP-Schwachstellenerkennung und Web API Fuzzing ist hier derzeit viel Bewegung zu beobachten. Neue Verfahren wie Symbolic Code Execution tragen zudem dazu bei, dass Fuzz-Testing noch effizienter und effektiver wird.
  3. Die Usability von Fuzzing Tools nimmt zu: Auch die Usability von Security-Testing-Plattformen nimmt zu, um Entwicklern den Einsatz von Fuzzing-Technologien so einfach wie möglich zu machen. In diesem Kontext kommen immer mehr CI/CD- und Dev-Tool-Integrationen auf den Markt, die ihnen die Instrumentierung und das initiale Fuzzing-Setup deutlich erleichtern. Autofuzz-Funktionen ermöglichen Entwicklern so zum Beispiel heute schon Fuzz-Tests in Docker aufzusetzen, ohne dass großes Vorwissen vorausgesetzt wird [12]. Alles mit einem einzigen Command – in weniger als 280 Zeichen.

Langfristig werden die eigentlichen Fuzzing-Technologien deshalb immer mehr in den Hintergrund treten, da sie bereits per default in Programmiersprachen, IDEs und Dev-Tools, integriert sind. Und wie bei jeder guten Technologie, wie zum Beispiel dem Smartphone oder dem Sicherheitsgurt, werden wir uns auch beim Fuzz-Testing in Zukunft die Frage stellen, wie wir früher ohne diese Technologie leben konnten. Einfach, weil es uns so natürlich erscheint, dass Software mit jedem Pull Request auch einen Security-Test durchläuft. Wie sollte man denn auch sonst sichere Software entwickeln? Wenn man dies nicht täte, würde man ja wissentlich Sicherheitslücken riskieren.

Autor

Dr. Khaled Yakdan

Dr. Khaled Yakdan ist Chief-Scientist und Co-Founder von Code Intelligence. Sein Team und er betreiben eine Plattform für automatisiertes Software Security Testing.
>> Weiterlesen
Das könnte Sie auch interessieren
Kommentare (0)

Neuen Kommentar schreiben