Suture ist ein statisches Spots-to- und hoher Bestellungs-Tool (für C) basierend auf LLVM IR und basiert auf Dr. Checker (dank seiner Schöpfer!) Zwei Highlights sind:
Wir nennen es Naht in der Hoffnung, dass es chirurgisch präzise sein kann, während sie in der Lage sind, mehrere Syscalls/Einstiegsfunktionen zusammen zu nähen, um Datenflüsse hohe Ordnung zu konstruieren. Weitere Informationen finden Sie in unserem Artikel: Entdecken Sie die Schwachstellen im unterdrückenden Stil in OS-Kerneln in ACM CCS'21 .
Zuerst klonen Sie das Repo:
~$ git clone https://github.com/seclab-ucr/SUTURE.git suture
Richten Sie dann die LLVM -Umgebung für die Naht ein:
~$ cd suture
~/suture$ python setup_suture.py -o ../suture_deps
Optionen (für setup_suture.py ):
-b Gibt den Zweignamen von LLVM an, der für die Naht eingerichtet werden soll. In diesem LLVM -Spiegel -Repo ist es standardmäßig "Release_90" (dh LLVM 9.0).-o gibt den Ordner an, um alle von Naht erforderlichen Dinge zu hosten (z. B. LLVM), und verwenden Sie einen beliebigen Ordner, den Sie bevorzugen. Abhängig von Ihrer Hardware kann das LLVM -Setup einige Zeit in Anspruch nehmen. Nach dem Abschluss wird eine SRCIPT -Datei mit dem Namen env.sh unter dem Nahtroot -Ordner generiert. Sie enthält Befehle, um die von der Naht verwendeten Umgebungsvariablen festzulegen.
Wichtig : Aktivieren Sie diese env.sh jedes Mal, bevor Sie Naht erstellen/verwenden (Sie können seine enthaltenen Befehle auch zu .bashrc für die automatische Aktivierung bei der Shell -Anmeldung hinzufügen!
~/suture$ source env.sh
Als nächstes werden wir Naht bauen:
~/suture$ cd llvm_analysis
~/suture/llvm_analysis$ ./build.sh
Bei einem erfolgreichen Build ist die Naht einsatzbereit.
Die Naht kann verwendet werden, um die schwierigen Schwachstellen mit hoher Ordnung außerhalb des Boxs zu entdecken. In diesem Abschnitt gehen wir diesen Prozess mit einem Beispiel durch (z. B. das motivierende Beispiel, wie in Abschnitt 2.1 in unserem Artikel gezeigt).
Um Schwachstellen zu ermitteln, erfordert Naht zwei Eingabearten: (1) Ein Programmmodul, das mit LLVM Bitcode (z. B. einer .bc- Datei) zusammengestellt wurde, und (2) eine Konfigurationsdatei für das Modul, das seine Eingangsfunktionen und benutzergesteuerten Argumente manifestiert.
Bereiten wir zuerst den LLVM -Bitcode für unser motivierendes Beispiel vor:
~/suture$ cd benchmark
~/suture/benchmark$ ./gen.sh motivating_example
HINWEIS : Aus Gründen der Einschätzung stellen wir gen.sh zur Erstellung von A .c zu .bc und .ll (menschliche lesbare LLVM -Bitcode) mit -O1 -Optimierungsstufe zur Verfügung.
Jetzt sollten wir den motivating_example.bc unter demselben Benchmark -Ordner haben, das ist das Eingabeprogrammmodul für die Naht.
Dann kommt es zur Konfigurationsdatei, wir haben bereits einen auf das motivierende Beispiel vorbereitet:
~/suture/benchmark$ cat conf_motivating_example
entry0 MY_IOCTL 1
entry1 NULL_ARG
entry2 NULL_ARG
Erläuterung : Jede Zeile in der Konfigurationsdatei beschreibt die Informationen einer Eintragsfunktion (z. B. die Funktion der obersten Ebene mit Anrufern und dient normalerweise als externe Schnittstelle) im Programmmodul, sie enthält bis zu 3 platzgetrennte Token:
entry_x MY_IOCTL 0_2 angeben.Wie oben gezeigt, gibt conf_motivating_example an, dass es in motivating_example drei Eintragsfunktionen gibt. Dies entspricht dem Code des motivierenden Beispiels.
Sobald der Programmbitcode und die Eintragskonfigurationsdatei fertig sind, können wir die Naht ausführen, um die Schwachstellen für die minderwertigen Schwachstellen zu entdecken:
~/suture$ ./run_nohup.sh benchmark/motivating_example.bc benchmark/conf_motivating_example
Erläuterung : run_nohup.sh ist ein einfaches Skript, das auf die kompilierte LLVM -Analyse des Nahtgänge aufgerufen wird:
~/suture$ ./run_nohup.sh [path/to/program.bc] [path/to/entry_func_config]
Nach dem Start ist je nach Hardware und Komplexität des Zielprogramms die erforderliche Zeit für die Naht, die die Analyse und die Erkennung von Sicherheitsanfällen abgeschlossen haben, sehr unterschiedlich. Ein einfaches Programm wie unser motivierendes Beispiel endet jedoch normalerweise sofort.
Entscheiden Sie, ob die Analyse abgeschlossen ist : Während der Ausführung hat die Naht weiterhin in einer Datei unter demselben Verzeichnis der Eintragskonfigurationsdatei angenommen. Angenommen, der Konfigurationsdateipfad ist /path/to/conf_Program , ist die Protokolldatei /path/to/conf_program.log . Wir können entscheiden, ob die Analyse endet, indem wir das Protokoll überwachen:
~/suture$ grep "Bug Detection Phase finished" benchmark/conf_motivating_example.log
Die oben genannte Protokolldatei ist ebenfalls die Ausgabe von Suture, die Naht wird ihre entdeckten potenziellen Schwachstellen in die Protokolldatei einbetten, die nach Abschluss der Analyse extrahiert und in einen endgültigen Warnbericht organisiert werden können:
~/suture$ ./ext_warns.sh benchmark/conf_motivating_example.log
Erläuterung : ext_warns.sh wird alle Warnungen (in JSON) extrahieren, die in die angegebene Protokolldatei eingebettet sind, sie in die endgültigen Warnberichte neu organisieren und ziemlich zeichnen. Die Warnberichte werden unter demselben Pfad der Protokolldatei in einen Ordner gesteckt. Angenommen, die Protokolldatei ist /path/to/conf_program.log . Der Warnberichtordner ist /path/to/warn-conf_program-yyyy-mm-dd .
~/suture$ ls benchmark/warns-conf_motivating_example-2021-11-10/
all int_overflow taint_data_use taint_loopbound taint_ptr_def
Im Ordner gibt es 5 Warnberichte, alle enthalten alle Arten von Warnungen, die nach ihrer Datenflussbeziehung zusammengefasst sind, während andere Berichte nur bestimmte Arten von Warnungen enthalten (z. B. Ganzzahlüberlauf, verdorbener Zeiger Dereference usw.), weitere Details darüber, wie wir Warnungen in unserer Arbeit gruppieren (Abschnitt 4). Normalerweise verwenden wir den einheitlichen Bericht nur alle .
~/suture$ cat -n benchmark/warns-conf_motivating_example-2021-11-10/all
1 =========================GROUP 0 (2 - 2)=========================
2 #####Warned Insts#####
3 (u'motivating_example.c', 30, [u'IntegerOverflowDetector'])
4 ######################
5
6 ++++++++++++++++WARN 0 (2 - 2)++++++++++++++++
7 IntegerOverflowDetector says: motivating_example.c@30 (bar : %add = add i8 %0, -16, !dbg !31)
8 ********Trace 0(2)********
9 #####CTX##### entry0
10 entry0 (motivating_example.c@18)
11 #####INSTS#####
12 >>>>>>>>>>>>>>>>>>tag: 0x55b206570420 tf: 0x55b20695b1b0 (2)>>>>>>>>>>>>>>>>>>
13 motivating_example.c@18 ( %cond = icmp eq i32 %cmd, 0, !dbg !31)
14 motivating_example.c@21 ( store i8 %user_input, i8* getelementptr inbounds (%struct.data, %struct.data* @d, i64 0, i32 1, i64 0), align 4, !dbg !32, !tbaa !34)
15 #####CTX##### entry1 -> bar
16 entry1 (motivating_example.c@35)
17 ----> (motivating_example.c@35 : %call = tail call i32 @bar(i8* bitcast (%struct.data* @d to i8*)), !dbg !27)
18 bar (motivating_example.c@30)
19 #####INSTS#####
20 >>>>>>>>>>>>>>>>>>tag: 0x55b2065e7050 tf: 0x55b2068174f0 (1)>>>>>>>>>>>>>>>>>>
21 motivating_example.c@30 ( %0 = load i8, i8* %add.ptr, align 1, !dbg !31, !tbaa !32)
22 motivating_example.c@30 ( %add = add i8 %0, -16, !dbg !31)
23
Erläuterung : Auf einer hohen Ebene enthält der Warnbericht einige Warngruppen , jede Gruppe enthält mehrere Warnungen , und jede Warnung enthält mehrere verdammte Spuren , die von einer Benutzereingabe stammen und eine sensible Programmanweisung versinken. Mit anderen Worten, eine Warnung wird für eine bestimmte Programmaussage und einen bestimmten Typ (z. B. Integer -Überlauf) erhoben, während eine Gruppe mehrere eng verwandte Warnungen aus der Sicht des Datenflusss enthält (siehe Abschnitt 4 in unserem Papier), sodass eine Gruppe möglicherweise mehrere Warnprogrammaussagen hat und unterschiedliche Warntypen enthält.
Nehmen Sie den obigen Warnbericht als Beispiel:
===GROUP No. (min_order - max_order)=== max_order wobei min_order die minimale Reihenfolge ist (z. B. einfach ausgedrückt , die Zeiten der Eingabefunktionen der Einstiegsfunktion in der Taint Propagation und Max.WARN No. lokal für ihre Gruppe ist.***Trace No. (order)*** , eine gemütliche Spur hat immer eine einzigartige Reihenfolge , die berechnet werden kann (z. B. keine Reichweite).Der Warnbericht zeigt eine gültige Anfälligkeit des Überlaufs in dem motivierenden Beispiel, während potenzielle Fehlalarme vermieden werden, die ein weniger präzises statisches Analyse -Tool generieren kann, können Details in Abschnitt 2.1 unseres Papiers gefunden werden.
Dieses Repo enthält auch einige andere Tools/Skripte, die Sie möglicherweise nützlich finden.
~/suture$ python llvm_analysis/AnalysisHelpers/EntryPointIdentifier/entry_point_identifier.py /path/to/prog_module.bc
~/suture$ cat /path/to/prog_module.bc.all_entries
Erläuterung : Dieses Skript kann einige gängige Eintragsfunktionen in einem Linux -Geräte -Treibermodul (z. B. ioctl () , read () , write ( ) usw. identifizieren, wodurch die Konstruktion der Eintragskonfigurationsdatei als Eingabe in die Naht beiträgt. Dieses Dienstprogramm wird hauptsächlich vom ursprünglichen Dr. Checker basierend auf einigen Kenntnissen der Kernel -Domäne (z. B. bestimmte Datenstrukturen wie Datei_operationen zur Definition der Treibereintragspunkte) implementiert. Wir haben dann einige Verbesserungen vorgenommen (z. B. die Heuristik robuster).
~/suture$ python flt_warns.py /path/to/warn_report [Regex] > /path/to/filtered_warn_report
Erläuterung : Aus unserer Erfahrung haben viele Fehlalarme in dem Warnbericht häufig eine gleiche problematische Unter-Taint-Trade (siehe Abschnitt 6.3 in unserem Artikel). Solange der Warnungsprüfer einen Fehlalarm inspiziert und die FP-induzierende Unterspanne erkennt, kann sie natürlich versuchen, alle anderen ähnlichen Fehlalarme mit demselben Unterverlauf automatisch auszuschließen, wodurch der von Rezensentservern wahrgenommene Fehlalarmrate verringert wird. Zu diesem Zweck stellen wir diesen einfachen FLT_WARARSS.Py bereit, der den ursprünglichen Warnbericht und einen regelmäßigen Ausdruck von Python als Eingänge nimmt. Dann wird er mit der RE gegen jede im Bericht übereinstimmende Merkmale übereinstimmen, wenn nach dem Stimmen der gemütliche Spur als falsche Alarm behandelt wird. Das Skript generiert einen neuen gefilterten Warnbericht mit Ausnahme aller übereinstimmenden Spuren.
Möglicherweise möchten Sie Naht als allgemeine statische Analyse verwenden (z. B. den Punkt-zu-/-Taint-Satz einer Variablen an einem bestimmten Programmort). Dies ist mit Sicherheit machbar, aber im Gegensatz zu der Erkennung von Anfälligkeit müssen Sie die Hände schmutzig und in den Code der Nutze eintauchen, um mit den Hauptdaten zu vertraut, die sie verwenden, und einige wichtige Funktionen und einige wichtige Funktionen und einige wichtige Funktionen. Ich hoffe, die folgenden Tipps können helfen:
LLVM entwickelt sich sehr schnell, ohne eine Garantie für die Rückwärtsverkehrsfähigkeit. Es ist sehr wahrscheinlich, dass Sie einige Kompilierungsfehler treffen, wenn Sie versuchen, die Naht mit einer neueren LLVM -Version (z. B.> 9.0) zu erstellen. Glücklicherweise sind solche Kompilierungsfehler normalerweise einfach zu lösen (z. B. müssen wir oft nur die veralteten LLVM-APIs durch die neueren ersetzen). Um die Naht an eine neuere LLVM -Version anzupassen, müssen wir zunächst eine neuere LLVM in 0x0 einrichten (z. B. müssen die Setup_Suture.py ändern, um LLVM -Repo aus einer aktiven Quelle zu klonen und den neueren Zweignamen anzugeben.