[PYTHON] Fuzzing und Statistiken

Einführung

Dieser Artikel fasst den statistischen Ansatz für das ** Seed-Scheduling-Problem ** des Faging zusammen. Die Grundlagen der Statistik und des intensiven Lernens, insbesondere die Binomialverteilung und Stichprobenprüfung sowie Probleme mit mehrarmigen Banditen, sind bekannt. Fuzzing ist eine Art Softwaretest zum Auffinden von Softwarefehlern (insbesondere Schwachstellen). Bei diesem Test werden dem zu testenden Programm eine Vielzahl von Eingaben gegeben und ausgeführt, und die Eingaben, die einige Probleme verursachen, werden aufgezeichnet. Es ist eine Methode. Natürlich können mehrere Eingaben denselben Fehler verursachen (Grundursache), sodass diese aufgezeichneten Eingaben dedupliziert werden, um 1: 1 mit dem Fehler in einem Triage-Prozess nach dem Fagging zu korrespondieren. ) Und in der Datenbank aufgezeichnet. Diese Reihe von Schritten wird als ** Fading-Kampagne ** bezeichnet. ossfuzz.png Googles OSS-Fuzz-Beispiel

Der größte Unterschied zum Zufallstest besteht darin, dass das Faging die Zustandsänderung beim Ausführen des Programms beobachtet (Beobachtung) und als Hinweis für die nächste Eingabegenerierung zurückmeldet. Fuzzing wird in die folgenden drei Typen eingeteilt, je nachdem, wie viele Informationen bei der Ausführung des Programms beobachtet werden.

Blackbox Fuzzing Beobachten Sie nur den Endstatus des Programms
Whitebox Fuzzing Beachten Sie auch die Semantik des Programms
Greybox Fuzzing Teilinformationen zum Programm beachten

Wenn Whitebox Fuzzing ein Programm für eine Eingabe ausführt, zeichnet es die gesamte Logik des ausgeführten Codeflusses auf und leitet die Bedingungen für die Generierung eines weiteren neuen Flusses mit dem SMT-Solver zur Eingabe der nächsten Eingabe ab. Generieren. Die sogenannte ** Symbolische Ausführung ** fällt in diese Kategorie. Teilinformationen in Graybox Fuzzing sind eine eher vage Definition, aber die meisten verwenden Abdeckungsinformationen, wenn das Programm ausgeführt wird. Dies wird insbesondere als ** Coverage Based (Greybox) Fuzzing ** bezeichnet. Beispielsweise beobachtet AFL die Kantenabdeckung, die beim Ausführen einer Eingabe vergeht, und behält diese Eingabe vorzugsweise bei, wenn sie eine noch nie gesehene Kante passiert.

FCS(Fuzzing Configuration Schedule) Jetzt werde ich das Seed-Scheduling-Problem des Hauptthemas erklären. Nach VALENTIN J.M. [^ 11] wird der Faging-Algorithmus wie folgt zusammengefasst. fuzzalgo.png

Dieses Dokument befasst sich mit dem Schedule () -Algorithmus, der die Seed-Planung innerhalb der obigen Schleife durchführt. Sie können sich den Startwert in Faging als Eingabedatei vorstellen. Der Vater generiert zuerst die folgende Eingabe basierend auf dem anfänglichen Startwert namens Initial Seed und fügt sie mit ConfUpdate () basierend auf den Feedback-Informationen zum Startpunktpool hinzu. Es gibt jedoch auch eine Methode namens ** Generationsbasiertes Fuzzing **, bei der der Startwert Metainformationen zur Erzeugung von Eingabewerten anstelle eines konkreten Werts wie PEACH-Vater verwendet, sodass der Startwert weiter als "Fuzzing-Konfiguration" verallgemeinert wird. Es ist üblich, es zu nennen. Dieses Dokument befasst sich mit dem allgemeineren ** Fuzzing Configuration Schedule (FCS) ** sowie der Seed-Planung.

Grey/White box FCS Der Zweck von Faging besteht darin, in einer bestimmten Zeit mehr Fehler zu erkennen. Daher ist die Frage, welcher Startwert (Konfiguration) zu einem bestimmten Zeitpunkt ausgewählt werden soll, ein wichtiger Faktor für die Gestaltung eines effizienten Faging. Als einfaches Beispiel wählt AFL vorzugsweise die ** kürzeste Programmausführungszeit ** unter den generierten Seeds aus. Dies ist eine Strategie, um innerhalb einer bestimmten Zeit mehr Samen zu erzeugen, indem Samen mit geringen Zeitkosten ausgewählt werden. AFF Fast [^ 5] zeichnet dagegen den vom Startwert ausgeführten Programmpfad auf und wählt vorzugsweise den Startwert aus, der weniger als ** Programmpfade ** passiert hat. Alternativ gibt es verschiedene Studien wie AFL Go [^ 7], eine Strategie, die Samen priorisiert, die leicht einen bestimmten Programmort erreichen können, eine Kombination mit statischer Analyse [^ 6] und eine Anwendung auf White-Box-Fuzzing [^ 4].

Black Box FCS mit einem statistischen Ansatz

Das obige Gray / White-Box-FCS verwendete Feedback wie Abdeckung und Programmpfad, aber was ist mit dem Black-Box-Fuzzer? Wie ich zu Beginn erklärt habe, beobachtet Black Box Fuzzing nur den Endstatus des Programms, sodass die erhaltenen Feedback-Informationen sehr klein sind. Aus diesem Grund hat das CERT-Team der CMU einen Black-Box-Fuzzer namens BFF entwickelt, aus jedem ausgewählten Startwert eine bestimmte Anzahl von Eingaben generiert und das Verhältnis der Eingaben, die die darin enthaltenen Fehler zugewiesen haben ** (#) Wir haben einen Algorithmus vorgeschlagen, bei dem Bugs / # ausgeführt werden) ** bevorzugt große Seeds auswählt. [^ 1] Genau genommen kann eine Mutation für einen Samen mit Faging als ** Bernoulli-Versuch ** angesehen werden, der eine bestimmte Anzahl von Eingaben aus einem Samen generiert, der Fehler mit einer Wahrscheinlichkeit p anzieht, und die Binomialverteilung zu diesem Zeitpunkt ist eine Poisson-Verteilung. Kann angenähert werden (weil die Wahrscheinlichkeit p sehr klein ist). Unten ist der Patch, den ich entwickelt habe, als ich die Binomialverteilung mit CERT BFF tatsächlich ausgegeben habe.

python


diff --git a/bff-2.8/batch.sh b/bff-2.8/batch.sh
index a7fb5ef22a..6c0af417df 100755
--- a/bff-2.8/batch.sh
+++ b/bff-2.8/batch.sh
@@ -66,7 +66,8 @@ contains() {
 scriptlocation=`echo "$(cd "$(dirname "$0")"; pwd)/"`
 echo Script location: $scriptlocation/bff.py
 platform=`uname -a`
-PINURL=https://software.intel.com/sites/landingpage/pintool/downloads/pin-3.0-76991-gcc-linux.tar.gz
+#PINURL=https://software.intel.com/sites/landingpage/pintool/downloads/pin-3.0-76991-gcc-linux.tar.gz
+PINURL=https://software.intel.com/sites/landingpage/pintool/downloads/pin-3.2-81205-gcc-linux.tar.gz
 if ( contains "$platform" "Darwin Kernel Version 11" ); then
     mypython="/Library/Frameworks/Python.framework/Versions/2.7/bin/python"
 else
diff --git a/bff-2.8/certfuzz/scoring/multiarmed_bandit/arms/base.py b/bff-2.8/certfuzz/scoring/multiarmed_bandit/arms/base.py
index 2fed07c3c3..47fd90477a 100644
--- a/bff-2.8/certfuzz/scoring/multiarmed_bandit/arms/base.py
+++ b/bff-2.8/certfuzz/scoring/multiarmed_bandit/arms/base.py
@@ -60,7 +60,8 @@ class BanditArmBase(object):
         self.successes = 0
         self.trials = 0
         self.probability = None
-
+        self.successratio = {}
+        
         # initialize probability
         self.update()
 
@@ -79,6 +80,7 @@ class BanditArmBase(object):
         '''
         self.successes += successes
         self.trials += trials
+        self.successratio[successes] = self.successratio.get(successes, 0) + trials
         self._update_p(successes, trials)
         if self.probability is None:
             logger.debug("MAB arm: %s", self)
@@ -86,7 +88,13 @@ class BanditArmBase(object):
         elif not (0.0 <= self.probability <= 1.0):
             logger.debug("MAB arm: %s", self)
             raise BanditArmError('probability must be between 0.0 <= {:f} <= 1.0'.format(self.probability))
-
+        if self.trials <= 0:
+            return
+        with open(str(id(self)) + ".dat", "w") as fp:
+            fp.write("# {} trials\n".format(self.trials))
+            for s in list(range(self.successes + 1)):
+                if s in self.successratio:
+                    fp.write("{} {}\n".format(s, float(self.successratio[s]) / float(self.trials)))
     def _update_p(self, *_unused_args):
         '''
         Internal method, ensure that self.probability gets assigned
diff --git a/bff-2.8/configs/bff.yaml b/bff-2.8/configs/bff.yaml
index 79d4d074a8..15197c559d 100644
--- a/bff-2.8/configs/bff.yaml
+++ b/bff-2.8/configs/bff.yaml
@@ -11,7 +11,7 @@
 #
 ##############################################################################
 campaign:
-    id: convert v5.2.0
+    id: LAVA-M v5.2.0
 
 
 ##############################################################################
@@ -31,8 +31,8 @@ campaign:
 #
 ##############################################################################
 target:
-    program: ~/convert
-    cmdline_template: $PROGRAM $SEEDFILE /dev/null
+    program: ~/who-lava
+    cmdline_template: $PROGRAM $SEEDFILE
 
 
 ##############################################################################
@@ -53,7 +53,7 @@ target:
 ##############################################################################
 
 directories:
-    seedfile_dir: seedfiles/examples
+    seedfile_dir: seedfiles/who
     working_dir: ~/fuzzing
     results_dir: results
 
diff --git a/bff-2.8/seedfiles/who/f1.utmp b/bff-2.8/seedfiles/who/f1.utmp
new file mode 100644
index 0000000000..b30aa294cf
Binary files /dev/null and b/bff-2.8/seedfiles/who/f1.utmp differ
diff --git a/bff-2.8/seedfiles/who/f2.utmp b/bff-2.8/seedfiles/who/f2.utmp
new file mode 100644
index 0000000000..201990c980
Binary files /dev/null and b/bff-2.8/seedfiles/who/f2.utmp differ
diff --git a/bff-2.8/seedfiles/who/f3.utmp b/bff-2.8/seedfiles/who/f3.utmp
new file mode 100644
index 0000000000..841846d9b8
Binary files /dev/null and b/bff-2.8/seedfiles/who/f3.utmp differ

patch

Wenn für jeden Startwert genügend Eingabegenerationen (Versuche) vorhanden sind, kann (# bugs / # run) als Bewertungswert verwendet werden, es ist jedoch unmöglich, alle Eingaben zu versuchen, die aus einem bestimmten Startwert generiert werden können. nahe. Daher generieren sie ungefähr 500 Eingaben für jeden Samen und verwenden die UCB-Obergrenze (Upper Confidence Bound) von ** 95% Konfidenzintervall ** als Bewertungswert als Probentest. Das FCS wurde so konzipiert, dass die Wahrscheinlichkeit, dass dieses UCB ausgewählt wird, umso höher ist, je größer der Startwert ist.

Mehrarmiges Banditenproblem beim Faging

Das im vorherigen Abschnitt erläuterte Black-Box-FCS nach Stichprobenschätzung ist ein sogenannter ** Online-Algorithmus **, und die korrekten Informationen darüber, wie viele fehlerhafte Eingaben ein Seed enthält, sind unbekannt. Mit zunehmender Anzahl von Versuchen verbessert sich daher auch die Qualität von UCB. Welches der Samen im Samenpool sollte also öfter probiert werden? Dies ist das sogenannte ** Explorations- und Ausbeutungsdilemma **. Für jeden Startwert kann der Bewertungswert "Leichtigkeit, Fehler zuzuweisen" von der im vorherigen Abschnitt erläuterten UCB berechnet werden. Sollen wir also irgendwann immer den Samen mit der höchsten Bewertung probieren? Oder gibt es etwas, das einen höheren Bewertungswert ergibt, wenn Sie einen anderen Samen auswählen und die Anzahl der Versuche erhöhen? In diesem Dilemma verwendet CERT BFF ϵ-gierig und EXP3.

mab.png

Gewichtetes Coupon Collector Problem und kein Theorem für das kostenlose Mittagessen

Es gibt jedoch tatsächlich ein Problem mit FCS von CERT BFF im vorherigen Abschnitt. Der Punkt ist, dass nur zwischen 0/1 unterschieden wird, ob die generierte Eingabe fehlerhaft ist oder nicht. Wie im ersten Abschnitt erläutert, ist die fehlerhafte Eingabe beim Faging im Grunde genommen ** mehrere Eingaben können denselben Fehler haben **. Angenommen, die folgende Eingabe wird für einen Startwert generiert.

python


0, 0, 0, 1, 0, 1, 0, 0, 1, 1,

Dies ist eine Bernoulli-Studie, die 4 fehlerhafte Eingaben mit einer Wahrscheinlichkeit von p in 10 Versuchen generiert hat. Wenn Sie jedoch tatsächlich jeden Fehler (Grundursache) untersuchen und kennzeichnen, kann dies wie folgt aussehen.

python


0, 0, 0, 1, 0, 2, 0, 0, 2, 2,

** Eigentlich habe ich nur zwei Arten von Bugs gezogen, Label 1 und 2 **. Im FCS von CERT BFF wird dies jedoch ebenfalls als 4 gezählt und der Probentest wird durchgeführt. Maverick Woo [^ 2] wies auf dieses Problem hin und zeigte, dass der FCS durch den konventionellen Bernoulli-Versuch nicht den richtigen Test durchführte. Selbst in der Faging-Kampagne mit CERT BFF traten viele Fehler auf, die unter der Mindestanzahl von EXP3-Bedauern lagen. Dies ist ein Beweis dafür, dass die herkömmliche Methode zur Bewertung von Saatgut weit von der Anzahl der Fehler nach dem Durchlaufen der Triage entfernt ist. Ich möchte also ein genaueres statistisches Modell verwenden, aber was ist los? Ich werde den vorherigen Test erneut veröffentlichen.

python


0, 0, 0, 1, 0, 2, 0, 0, 2, 2,

Angenommen, Sie generieren auch 10 Eingaben aus anderen Samen, und jetzt haben Sie:

python


0, 0, 0, 1, 0, 2, 0, 0, 3, 4,

Anscheinend konnte dieser Samen vier Arten von Käfern finden. In diesem Fall sollte der letztere Startpunkt intuitiv mit Priorität ausgewählt werden.

Mit anderen Worten, ** Ich möchte den Samen priorisieren, der in einer bestimmten Anzahl von Versuchen mehr Arten von Fehlern aus N Arten von Fehlern anzieht **. Dies kann genau als [Coupon Collector Problem](https://ja.wikipedia.org/wiki/Coupon Collector Problem) modelliert werden. Da die Wahrscheinlichkeit, jeden Fehler zuzuweisen, unterschiedlich ist, verwenden Sie WCCP (Weighted Coupon Collector Problem), um genau zu sein. .. Leider kann WCCP nicht modelliert werden, ohne die Verteilung der Coupongewichte zu kennen. Dies bedeutet also, dass es keine Strategie gibt, um Black Box FCS für ein Programm zu optimieren, als das No Free Ranch-Theorem. Maverick Woo [^ 2] zeigte dies und schlug eine Methode namens Dreierregel als 50-50-Plan vor und entwickelte ein System namens FuzzSim, das mithilfe eines Offline-Algorithmus unter Verwendung dynamischer Programmierung den richtigen optimalen FCS-Wert findet. Ich bin ein wenig begeistert. Wenn Sie an diesen Details interessiert sind, lesen Sie bitte das Papier.

Dr. Maverick Woo ist übrigens mein Ausbilder an der CMU.

abschließend

Dieses Mal habe ich Black Box FCS als einen der statistischen Ansätze für das Faging eingeführt. Wenn Sie interessiert sind, gibt es auch eine Studie, die ein statistisches Modell [^ 3] verwendet, um den frühesten ersten Samen auszuwählen.

Reference

Recommended Posts

Fuzzing und Statistiken
Grundlegende Statistik und Gaußsche Verteilung
Aktienkurs und Statistik (Mittelwert, Standardabweichung)
Über _ und __
[Statistik für Programmierer] Bedingter Wahrscheinlichkeits- und Multiplikatorsatz
[Statistik für Programmierer] Lorenzkurve und Gini-Koeffizient