NPA: Fuzzing AusweisAPP

From
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

zugehöriger Vortrag vom 01.10.2010

Fuzzing

Grundsätzlich lässt sich Fuzzing als automatisierte Eingabemanipulation verstehen.

Das dem Fuzzing am nähesten kommende Verfahren, die "boundary value analysis" ist eine Methode bei der die Aunahmebehandlung mit Testwerten um die Grenze zwischen guten und schlechten Werten herum überprüft wird.

Zusätzlich zu den Grenzwerten sind für das Fuzzing aber generell alle Werte interessant die undefiniertes oder unsicheres Verhalten hervorrufen können.


Fuzzing nach Sutton et al.
„... method for discovering faults in software by providing unexpected input and monitoring for exceptions ...“ [MSAGPA S.22]


Weiterhin hat Fuzzing Ähnlichkeit mit bekannten Testverfahren wie "Black Box Testing" und Gray Box Testing", wobei Zweiteres dank Systemwissen einen deutlich höheren Erfolg verspricht.

Historie

Die erste Refernz zu Fuzzing ist aus dem Jahr 1989, als Prof Barton Miller von der UW-Madison Robustheitstests von Unix Anwendungen durchführen ließ. Dabei wurden Zufällige Zeichen und Zeichenketten an die Applikationen gesendet. Ziel war die Qualität des Codes und Zuverlässigkeit der Programme zu erhöhen.

Der nächste Meilenstein war 1999 die PROTOS Testsuite der Oula University, die für diverse Protokolle fehlerhafte nicht dem Protokoll entsprechende Pakete erzeugte.

In den Jahren ab 2002 machte sich das gesteigerte Interesse an Fuzzing durch die Veröffentlichung diverser Fuzzing Frameworks bemerkbar. Dazu gehören u.a. Spike und das kommerzielle Codenomicon.

Funktionsweise

am Phasenmodell von Sutton et al [MSAGPA S.29]

Identify Target
Neben der Wahl der Anwendung an sich ist das eigentliche Einfallstor, wie eine Datei, eine Schnittstelle oder eine Bibliothek interessant;wobei vielfach verwendete wegen ihrer großen Verbreitung vorzuziehen sind.

Bei der Zielauswahl sind bereits bekannte Schwachstellen des selben Herstellers (auch in anderen Produkten) besonders interessant.

Identify Inputs
Schwachstellen entstehen fast immer durch ungenügende Eingabedatenprüfung, diese können neben direkten Nutzereingaben unter anderem Header, Dateinamen, Umgebungsvariablen oder Registry Einträge sein.

Generate Fuzzed Data
Je nach Ziel und Datenformat sollten Daten jeweils automatisiert vorausgewählt, aus sich heraus mutiert/verändert oder dynamisch neu generiert werden.

Execute Fuzzed Data
Der eigentliche Prozess des Sendens vom Paketes, Öffnens der Datei oder Startens des Prozesses.

Monitor for Exceptions
Die Fehlererkennung dient dann zur Eingrenzung des Problemfalles oder der Testfälle, sollte etwa die Reihenfolge/Abfolge eine Rolle spielen. Ohne sie weiß man zwar von der Existenz eines Fehlers, kann ihn aber nicht lokalisieren.

Determine Exploitability
Mit der Fehlerursache kann, je nach Ziel, von einem Sicherheitsspezialisten der Fehler direkt behoben werden oder nach Folgefehlern gesucht werden. Im Gegensatz zu den anderen Phasen ist diese nicht automatisiert.

Datengenerierung

Je nachdem wie die Daten generiert werden, unterscheidet man Fuzzer in die folgenden beiden Klassen.

Mutationsbasiert
Es werden vorhandene Daten genommen und kontinuierlich verändert.

Erzeugungsbasiert
Die Daten werden nach Regeln jedes mal von neu generiert, je nach Ziel z.B. ein Paket oder eine Datei.

Es gibt aber noch weitere Arten, die mehr oder minder Effizient sind, wie Fuzzer funktionieren können.

  • Bereits im Vorhinein per Hand erstellte Testfälle
  • komplett Zufällig
while [1]; do cat /dev/urandom | nc -vv target port; done
  • Manuelle Protokoll Mutation

Ein Mensch „generiert“ selbst die möglichen Fehlerhaften Daten, gibt sie ein und nur noch der Prozess drum herum automatisiert ist.

Beispiele

Integer

Bei Betrachtung des Folgenden Beispiels mit Zugriff auf die Integer Variable size ist der Grenzfall max-1 ([2^32]-1) kritisch, wenn ein Over- oder Underflow das Ziel ist.

buffer = (char*) malloc(size + 1);  //+1 für Nullterminierung

Statt +1 zu addieren können auch andere Operationen mit size vorgenommen werden. Beispielsweise Subtraktion, falls nur Teile der Eingabe ausgelesen werden sollen, oder Multiplikation, im Falle einer Formatumwandlung in Unicode. Daher sind folgende Fälle mit nicht zu großem n und max = (2^32)-1 interessant:

  • 0,1, … , n
  • max, max-1, … , max-n;
  • max/2, max/2-1, … . max/2-n
Strings

Lange Zeichenketten, beispielsweise 5000 x ein 'A' oder anderes ASCII Zeichen.

Feldbegrenzer

Mit oft verwendete Feldbegrenzer-Zeichen in der Eingabe besteht eine höhere Wahrscheinlichkeit mehr Code abzudecken, da so mehrere Eingaben bzw. eine Folgeeingabe erreicht werden kann.

Bsp: /, ', „, \,  , ., <, >, ;, :
Format Strings

Wie %d, %s, %n die meist zu einem lesenden Speicherzugriff führen habe eine höhrere Chance Speicherzugriffsverletzungen auszulösen.

Directory Traversal

Wenn an einer Stelle ein Filename übermittelt werden kann, so kann mittels Präfix z.B. ../../filename auf andere als den gewollten Ort zugegriffen werden.

Command Injection

Werden Eingabe direkt an Befehle des Betriebssystems angehängt besteht unter UNIX die Möglichkeit neben der Eingabe mit einem Verkettungsoperator ein weiteres Kommando abzusetzen.

System(„ls /“ + eingabe); //kann zu „ls /usr && rm -rf /“ werden

Grenzen

Fuzzing kann nur ganz bestimmte Schwächen im Ziel herausfinden und es ist auch begrenzt was die Arten von Schwächen angeht. Im folgenden erläutert an einigen Schwächeklassen.

Zugriffskontrolle
Selbst wenn ein Fehler gefunden wird kann der Fuzzer nicht unbedingt unterscheiden ob der Zustand den er erreicht hat durch eine Zugriffskontrolle geschützt war, er also im admin Bereich war oder nicht. Dazu müsste er speziell darauf ausgelegt sein.

Schwacher Logikentwurf
Eine Funktion die in ihrer Grundheit an sich unsicher ist wie ein offener Fernzugriff in irgend einer Form kann so einfach nicht erkannt werden wenn es kein Fehlerfall in der Software ist und es z.B. vergessen wurde diesen Zugriff vor der Veröffentlichung wieder zu entfernen.

Hintertüren
Ein Backdoor unterscheidet sich für den Fuzzer nicht von einer anderen Eingabemöglichkeit und wenn ihm die Logik zur Steuerung dessen fehlt kann er damit auch nicht viel anfangen. Selbst wenn er Zugriff erhält muss er das schon mitbekommen. Einen Absturz dagegen würde er bemerken.

Memory Corruption
Speicherfehler können, ohne Debugger im Zielprozess, nicht erkannt werden wenn der Fehler abgefangen und behandelt wird.

Schwachstellenkombination
Kombinationen von Schwachstellen für einen Zugriff oder auch wenn die Reihenfolge wichtig ist sind von Fuzzern nicht sinnvoll herauszufinden.

Effektivität

Die Reproduzierbarkeit der Ergebnisse ist eine Grundanforderung die vom Fuzzer bereitgestellt werden muss, damit die ermittelten Ergebnisse verwendbar sind. Es sollten also alle Testfälle aufgezeichnet werden um auch solche Fehler nachstellen zu können die von vorherigen Tests abhängig sind.

Wiederverwendbarkeit von Teilen des Fuzzers für verschiedene Ziele verringert den Arbeitsaufwand, analog zur Idee eines Frameworks. Bei Aufteilung in die Module Datengenerierung, Testausführung und Fehlerkennung muss bei wechselnden Daten nur die Datengenerierung modifiziert werden.

Das Verständnis der Konzepte von Prozesszustand und Prozesstiefe hilft bei der Fehlerabdeckung und damit auch bei der Eingrenzung der Testfälle. Eine Eingabe in einem Zustand führt zu einem weiteren Zustand der durch die Eingabe tiefer im Prozess liegt. Eine andere Eingabe könnte aber wiederum zu einem anderen Folgezustand geführt haben. Veranschaulichen lässt es sich an einem Baum, der für jede Eingabe einen anderen Kindknoten haben kann. Damit würden sich deutlich mehr zu fuzzende Pfade in dem Programm ergeben. Es wäre wichtig zu wissen ob je nach Eingabe in der Tiefe andere Zustände erreicht werden können um an diesen gegebenenfalls weiter zu fuzzen, sollten sie existieren.

Wie viele Zustände des Prozesses während des Fuzzingprozesses erreicht werden gibt die Codeabdeckung wieder. Diese kann ein Maß für den Umfang des Testens dienen.

Das Erkennen eines Fehlerzustandes in der Zielanwendung ist unbedingt erforderlich um Ergebnisse in irgend einer Form zu produzieren. Eine Möglichkeit wäre mit einem „ping“ den Zielcomputer zu überwachen und gegebenenfalls seinen Absturz zu bemerken. Mit Zugriff auf das Zielsystem können auch Logs der Anwendung oder System Logs genutzt werden. Das gilt aber nur solange die Fehler nicht von irgend einer Form von Ausnhamebehandlung abgefangen werden. Eine bessere Möglichkeit ist Zugriff auf einen Debugger in der Zielanwendung, der jedoch Plattformspezifisch ist.

Fuzzer

Lokal

Weil der Zugriff zum System bereits Möglich ist, sind Wege interessant um an die Administratorrechte zu kommen. Als Möglichkeit bieten sich Programme mit setuid Bit an.

  • Kommandozeile: Es wird an den Übergabeparametern an die Anwendung gefuzzt.
  • Umgebungsvariable: Vom Programm genutzte Umgebungsvariablen werden modifiziert.
  • Dateiformat: Eine vom Ziel verarbeitete Datei wird entsprechend vorbereitet um beim Auslesen ungewolltes Verhalten zu erzeugen.
  • Speicher: Der Arbeitsspeicher wird eingefroren, die fehlerhaften Daten in die Routinen der Eingabeparser eingefügt und das Ergebnis abgewartet. Nach jedem Test wird das Speicherabbild vom einfrieren wieder hergestellt.

Remote

Eine Schwäche in entfernten Anwendungen kann einem Angreifer Zugang zu den gespeicherten Daten oder weiter zum darunterliegenden System ermöglichen.

Ziele

  • Netzwerk Protokolle wie FTP oder MSRPC
  • Web Anwendungen
    • um via HTTP am Ziel z.B. SQL injection oder Cross Site Scripting zu betreiben
    • Tools: WebScarab, SPI Fuzzer, Codenomicon HTTP Test Tools
  • Web Browser
    • und die darin enthaltenen Parser für z.B. HTML, CSS, COM, DOM, ActiveX

Frameworks

Fuzzing Frameworks abstrahieren oft benötigte Komponenten von Fuzzern und sind so Wiederverwendbar für die verschiedensten Typen von Fuzzern. Beispielhaft wäre die Datenerzeugung von typischen Problemfällen für Parser oder Abstraktion von Ein-und Ausgabe für Netzwerk oder Datenträger zu nennen. Durch das konzentrierte und breit anwendbare Wissen in einem Framework gibt es mehr Beteiligte und es fließt damit potenziell mehr Wissen und Arbeit in ein Framework.

Nachteile sind die hohe Komplexität, welche die Vielseitigkeit ermöglicht, und der damit verbundene Einarbeitungsaufwand sowie mögliche Nichtabdeckung des benötigten Ziels.

Analyse der AusweisApp

Laufzeitanalyse

Statische Analyse

Funktionsweise

Kommunikation der AusweisApp

Fuzzing der Ausweisapp

Mitschnitt Kommunikation

Fuzzing Frameworks

weiterführende Ansätze

Software

Literatur

  • [MSAGPA] Sutton Michael/Greene Adam/Amini Pedram: FUZZING Brute Force Vulnerability Discovery