
JAW: Ein Graph-basiertes Sicherheitsanalyse-Framework für clientseitiges JavaScript
J A W
Webseite | Dokumentation | Einrichtung | Crawler | Schnellstart Docker (Beispiel)
Eine quelloffene, prototypische Implementierung von Property-Graphen für JavaScript, basierend auf dem esprima-Parser und der EsTree SpiderMonkey Spec. JAW kann zur Analyse der Client-Seite von Webanwendungen und JavaScript-basierten Programmen verwendet werden.
Dieses Projekt ist unter der GNU AFFERO GENERAL PUBLIC LICENSE V3.0 lizenziert. Weitere Informationen finden Sie hier.
JAW besitzt eine Github-Pages-Website unter https://soheilkhodayari.github.io/JAW/.
Versionshinweise:
JAW-V2.JAW-V1.Die Architektur von JAW ist unten dargestellt.
JAW kann auf zwei verschiedene Arten verwendet werden:
Beliebige JavaScript-Analyse: Verwenden Sie JAW zur Modellierung und Analyse eines beliebigen JavaScript-Programms, indem Sie den Dateisystem-pfad des Programms angeben.
Webanwendungsanalyse: Analysieren Sie eine Webanwendung, indem Sie eine einzelne Start-URL angeben.
Verwenden Sie die gesammelten Webressourcen, um einen Hybriden Programmgraphen (HPG) zu erstellen, der in eine Neo4j-Datenbank importiert wird.
Optional können Sie dem HPG-Konstruktionsmodul eine Zuordnung von semantischen Typen zu benutzerdefinierten JavaScript-Sprachtokens bereitstellen, was die Kategorisierung von JavaScript-Funktionen nach ihrem Zweck (z. B. HTTP-Anforderungsfunktionen) erleichtert.
Fragen Sie die erstellte Neo4j-Graphendatenbank für verschiedene Analysen ab. JAW bietet Dienstprogramm-Traversierungen für Datenflussanalyse, Kontrollflussanalyse, Erreichbarkeitsanalyse und Mustervergleich. Diese Traversierungen können zur Entwicklung benutzerdefinierter Sicherheitsanalysen verwendet werden.
JAW enthält auch integrierte Traversierungen zur Erkennung von Client-seitigem CSRF, DOM Clobbering- und Request-Hijacking-Schwachstellen.
Die Ausgaben werden im selben Ordner wie die Eingabe gespeichert.
Das Installationsskript setzt Folgendes voraus:
npm package manager (node js)python 3.xpip-PaketmanagerInstallieren Sie anschließend die erforderlichen Abhängigkeiten mit:
$ ./install.sh
Detaillierte Installationsanweisungen finden Sie hier.
Sie können eine Instanz der Pipeline in einem Hintergrund-Screen ausführen mit:
$ python3 -m run_pipeline --conf=config.yaml
Die CLI bietet folgende Optionen:
$ python3 -m run_pipeline -h
usage: run_pipeline.py [-h] [--conf FILE] [--site SITE] [--list LIST] [--from FROM] [--to TO]
Dieses Skript führt die Tool-Pipeline aus.
optionale Argumente:
-h, --help zeigt diese Hilfemeldung und beendet das Programm
--conf FILE, -C FILE Pipeline-Konfigurationsdatei. (Standard: config.yaml)
--site SITE, -S SITE zu testende Website; überschreibt Konfigurationsdatei (Standard: None)
--list LIST, -L LIST zu testende Site-Liste; überschreibt Konfigurationsdatei (Standard: None)
--from FROM, -F FROM erster Eintrag, der bei einer Site-Liste berücksichtigt werden soll; überschreibt Konfigurationsdatei (Standard: -1)
--to TO, -T TO letzter Eintrag, der bei einer Site-Liste berücksichtigt werden soll; überschreibt Konfigurationsdatei (Standard: -1)
Eingabekonfiguration: JAW erwartet eine .yaml-Konfigurationsdatei als Eingabe. Ein Beispiel finden Sie in config.yaml.
Hinweis. Die Konfigurationsdatei gibt verschiedene Durchläufe (z. B. Crawling, statische Analyse, etc.) an, die für jede Schwachstellenklasse aktiviert oder deaktiviert werden können. Dies ermöglicht es, die Bausteine des Tools einzeln oder in einer anderen Reihenfolge auszuführen (z. B. zuerst alle Web-Apps crawlen, dann die Sicherheitsanalyse durchführen).
Um ein kurzes Beispiel auszuführen, das zeigt, wie man einen Property-Graphen erstellt und Cypher-Abfragen darüber ausführt, tun Sie Folgendes:
$ python3 -m analyses.example.example_analysis --input=$(pwd)/data/test_program/test.js
Dieses Modul sammelt die für Tests benötigten Daten (d. h. JavaScript-Code und Zustandswerte von Webseiten). Wenn Sie eine bestimmte JavaScript-Datei testen möchten, die Sie bereits auf Ihrem Dateisystem haben, können Sie diesen Schritt überspringen.
JAW verfügt über Crawler, die auf Selenium (JAW-v1), Puppeteer (JAW-v2, v3) und Playwright (JAW-v3) basieren. Für aktuellste Funktionen wird empfohlen, die Puppeteer- oder Playwright-basierten Versionen zu verwenden.
Dieser Webcrawler verwendet foxhound, eine instrumentierte Version von Firefox, um dynamisches Taint-Tracking durchzuführen, während er durch Webseiten navigiert. Starten Sie den Crawler mit:
$ cd crawler
$ node crawler-taint.js --seedurl=https://google.com --maxurls=100 --headless=true --foxhoundpath=<optionaler-foxhound-ausführbarer-pfad>
Der foxhoundpath ist standardmäßig auf das folgende Verzeichnis gesetzt: crawler/foxhound/firefox, das eine Binärdatei namens firefox enthält.
Hinweis: Sie benötigen einen Build von foxhound, um diese Version zu verwenden. Ein Ubuntu-Build ist im JAW-v3-Release enthalten.
Starten Sie den Crawler mit:
$ cd crawler
$ node crawler.js --seedurl=https://google.com --maxurls=100 --browser=chrome --headless=true
Weitere Informationen finden Sie hier.
Starten Sie den Crawler mit:
$ cd crawler/hpg_crawler
$ vim docker-compose.yaml # hier die zu crawelnden Websites eintragen und speichern
$ docker-compose build
$ docker-compose up -d
Weitere Informationen finden Sie in der Dokumentation des hpg_crawler hier.
Um einen HPG für eine (oder mehrere) JavaScript-Datei(en) zu erzeugen, führen Sie Folgendes aus:
$ node engine/cli.js --lang=js --graphid=graph1 --input=/in/file1.js --input=/in/file2.js --output=$(pwd)/data/out/ --mode=csv
optionale Argumente:
--lang: Sprache des Eingabeprogramms
--graphid: eine Kennung für den erstellten HPG
--input: Pfad des/der Eingabeprogramms/e
--output: Pfad des Ausgabe-HPG, muss ein Verzeichnis sein
--mode: bestimmt das Ausgabeformat (csv oder graphML)
Um einen HPG in eine Neo4j-Graphendatenbank (Docker-Instanz) zu importieren, führen Sie Folgendes aus:
$ python3 -m hpg_neo4j.hpg_import --rpath=<pfad-zum-ordner-der-csv-dateien> --id=<xyz> --nodes=<nodes.csv> --edges=<rels.csv>
$ python3 -m hpg_neo4j.hpg_import -h
usage: hpg_import.py [-h] [--rpath P] [--id I] [--nodes N] [--edges E]
Dieses Skript importiert eine CSV eines Property-Graphen in eine Neo4j-Docker-Datenbank.
optionale Argumente:
-h, --help zeigt diese Hilfemeldung und beendet das Programm
--rpath P relativer Pfad zum Ordner, der die Graph-CSV-Dateien enthält, innerhalb des `data`-Verzeichnisses
--id I eine Kennung für den Graphen oder Docker-Container
--nodes N der Name der Knoten-CSV-Datei (Standard: nodes.csv)
--edges E der Name der Beziehungs-CSV-Datei (Standard: rels.csv)
Um einen hybriden Property-Graphen für die Ausgabe des hpg_crawler zu erstellen und in eine lokale Neo4j-Instanz zu importieren, können Sie auch Folgendes tun:
$ python3 -m engine.api <pfad> --js=<program.js> --import=<bool> --hybrid=<bool> --reqs=<requests.out> --evts=<events.out> --cookies=<cookies.pkl> --html=<html_snapshot.html>
Spezifikation der Parameter:
<pfad>: absoluter Pfad zum Ordner mit den Programmdateien für die Analyse (muss unter dem Ordner engine/outputs liegen).--js=<program.js>: Name des JavaScript-Programms für die Analyse (Standard: js_program.js).--import=<bool>: ob der erstellte Property-Graph in eine aktive Neo4j-Datenbank importiert werden soll (Standard: true).--hybrid=bool: ob der Hybridmodus aktiviert ist (Standard: false). Dies bedeutet, dass der Tester den Property-Graphen durch Eingabe von Dateien für HTML-Snapshot, ausgelöste Ereignisse, HTTP-Anfragen und Cookies, wie vom JAW-Crawler gesammelt, anreichern möchte.--reqs=<requests.out>: nur für Hybridmodus, Name der Datei mit der Sequenz der beobachteten Netzwerkanfragen; übergeben Sie den String false, um sie auszuschließen (Standard: request_logs_short.out).--evts=<events.out>: nur für Hybridmodus, Name der Datei mit der Sequenz der ausgelösten Ereignisse; übergeben Sie den String , um sie auszuschließen (Standard: ).Weitere Informationen finden Sie in der Hilfs-CLI der Graph-Konstruktions-API:
$ python3 -m engine.api -h
Der erstellte HPG kann dann mit Cypher oder dem NeoModel ORM abgefragt werden.
Sie sollten Ihre Abfragen in analyses/<ANALYSE_NAME> platzieren und ausführen.
Sie können das NeoModel ORM verwenden, um den HPG abzufragen. So schreiben Sie eine Abfrage:
example_query_orm.py im Ordner analyses/example.$ python3 -m analyses.example.example_query_orm
Weitere Informationen finden Sie hier.
Sie können Cypher verwenden, um benutzerdefinierte Abfragen zu schreiben. Gehen Sie dafür wie folgt vor:
example_query_cypher.py im Ordner analyses/example.$ python3 -m analyses.example.example_query_cypher
Weitere Informationen finden Sie hier.
Dieser Abschnitt beschreibt, wie JAW zur Schwachstellenerkennung konfiguriert und verwendet wird und wie die Ausgabe zu interpretieren ist. JAW enthält unter anderem eigenständige Abfragen zur Erkennung von Client-seitigem CSRF und DOM Clobbering.
Schritt 1. Aktivieren Sie die Analysekomponente für die Schwachstellenklasse in der Eingabe-config.yaml-Datei:
request_hijacking:
enabled: true
# [...]
open_redirect:
enabled: false
# [...]
domclobbering:
enabled: false
# [...]
cs_csrf:
enabled: false
# [...]
Schritt 2. Führen Sie eine Instanz der Pipeline aus mit:
$ python3 -m run_pipeline --conf=config.yaml
Hinweis. Sie können mehrere Instanzen der Pipeline unter verschiedenen screens ausführen:
$ screen -dmS s1 bash -c 'python3 -m run_pipeline --conf=conf1.yaml; exec sh'
$ screen -dmS s2 bash -c 'python3 -m run_pipeline --conf=conf2.yaml; exec sh'
$ # [...]
Um parallele Konfigurationsdateien automatisch zu generieren, können Sie das Skript generate_config.py verwenden.
Die Ausgaben werden in einer Datei namens sink.flows.out im selben Ordner wie die Eingabe gespeichert. Bei Client-seitigem CSRF beispielsweise gibt JAW für jede erkannte HTTP-Anfrage einen Eintrag aus, der den Satz semantischer Typen (auch semantische Tags oder Labels genannt) markiert, die mit den die Anfrage konstruierenden Elementen (d. h. den Programmslices) verbunden sind. Eine mit dem semantischen Typ ['WIN.LOC'] markierte HTTP-Anfrage ist beispielsweise über den window.location-Injektionspunkt fälschbar. Eine mit ['NON-REACH'] markierte Anfrage ist jedoch nicht fälschbar.
Ein beispielhafter Ausgabeeintrag ist unten dargestellt:
[*] Tags: ['WIN.LOC']
[*] NodeId: {'TopExpression': '86', 'CallExpression': '87', 'Argument': '94'}
[*] Location: 29
[*] Function: ajax
[*] Template: ajaxloc + "/bearer1234/"
[*] Top Expression: $.ajax({ xhrFields: { withCredentials: "true" }, url: ajaxloc + "/bearer1234/" })
1:['WIN.LOC'] variable=ajaxloc
0 (loc:6)- var ajaxloc = window.location.href
Dieser Eintrag zeigt, dass es in Zeile 29 einen $.ajax-Aufrufausdruck gibt, der eine ajax-Anfrage mit der URL-Vorlage ajaxloc + "/bearer1234/" auslöst, wobei der Parameter ajaxloc ein Programmslice ist, der seinen Wert in Zeile 6 von window.location.href liest, also über ['WIN.LOC'] fälschbar ist.
Um den Testprozess für JAW zu optimieren und sicherzustellen, dass Ihr Setup korrekt ist, stellen wir eine einfache Node.js-Webanwendung bereit, mit der Sie JAW testen können.
Zuerst installieren Sie die Abhängigkeiten:
$ cd tests/test-webapp
$ npm install
Führen Sie dann die Anwendung in einem neuen Screen aus:
$ screen -dmS jawwebapp bash -c 'PORT=6789 npm run devstart; exec sh'
Weitere Informationen finden Sie auf unserer Wiki-Seite hier. Nachfolgend finden Sie ein Inhaltsverzeichnis für den schnellen Zugriff.
Pull-Requests sind jederzeit willkommen. Dieses Projekt soll ein sicherer, einladender Raum sein, und die Mitwirkenden werden gebeten, den Verhaltenskodex für Mitwirkende einzuhalten.
Wenn Sie JAW für akademische Forschung verwenden, empfehlen wir Ihnen, das folgende Paper zu zitieren:
@inproceedings{JAW,
title = {JAW: Studying Client-side CSRF with Hybrid Property Graphs and Declarative Traversals},
author= {Soheil Khodayari and Giancarlo Pellegrino},
booktitle = {30th {USENIX} Security Symposium ({USENIX} Security 21)},
year = {2021},
address = {Vancouver, B.C.},
publisher = {{USENIX} Association},
}
JAW hat einen langen Weg zurückgelegt und wir möchten unseren Mitwirkenden hier eine wohlverdiente Anerkennung aussprechen!
falseevents.out--cookies=<cookies.pkl>: nur für Hybridmodus, Name der Datei mit den Cookies; übergeben Sie den String false, um sie auszuschließen (Standard: cookies.pkl).--html=<html_snapshot.html>: nur für Hybridmodus, Name der Datei mit dem DOM-Baum-Snapshot; übergeben Sie den String false, um ihn auszuschließen (Standard: html_rendered.html).