
JAW: Un Framework de Análisis de Seguridad Basado en Grafos para JavaScript del Lado del Cliente
J A W
Sitio web | Documentación | Instalación | Rastreador | Inicio rápido Docker (Ejemplo)
Una implementación prototipo de código abierto de grafos de propiedades para JavaScript basada en el analizador esprima y en la especificación EsTree SpiderMonkey Spec. JAW se puede utilizar para analizar el lado cliente de aplicaciones web y programas basados en JavaScript.
Este proyecto está licenciado bajo GNU AFFERO GENERAL PUBLIC LICENSE V3.0. Consulte aquí para más información.
JAW tiene un sitio web en Github Pages disponible en https://soheilkhodayari.github.io/JAW/.
Notas de publicación:
JAW-V2.JAW-V1.La arquitectura de JAW se muestra a continuación.
JAW se puede utilizar de dos maneras distintas:
Análisis de JavaScript arbitrario: Utilice JAW para modelar y analizar cualquier programa JavaScript especificando la ruta del sistema de archivos del programa.
Análisis de aplicaciones web: Analice una aplicación web proporcionando una única URL semilla.
Utilice los recursos web recolectados para crear un Grafo de Programa Híbrido (HPG), que se importará a una base de datos Neo4j.
Opcionalmente, suministre al módulo de construcción del HPG un mapeo de tipos semánticos a tokens personalizados del lenguaje JavaScript, facilitando la categorización de funciones JavaScript según su propósito (por ejemplo, funciones de petición HTTP).
Consulte la base de datos de grafos Neo4j construida para diversos análisis. JAW ofrece recorridos utilitarios para análisis de flujo de datos, análisis de flujo de control, análisis de alcanzabilidad y emparejamiento de patrones. Estos recorridos se pueden utilizar para desarrollar análisis de seguridad personalizados.
JAW también incluye recorridos integrados para detectar vulnerabilidades de CSRF del lado cliente, DOM Clobbering y secuestro de peticiones.
Las salidas se almacenarán en la misma carpeta que la entrada.
El script de instalación requiere los siguientes prerrequisitos:
npm package manager (node js)python 3.xpip package managerDespués, instale las dependencias necesarias mediante:
$ ./install.sh
Para instrucciones de instalación detalladas, consulte aquí.
Puede ejecutar una instancia del pipeline en una pantalla de fondo mediante:
$ python3 -m run_pipeline --conf=config.yaml
La CLI ofrece las siguientes opciones:
$ python3 -m run_pipeline -h
usage: run_pipeline.py [-h] [--conf FILE] [--site SITE] [--list LIST] [--from FROM] [--to TO]
This script runs the tool pipeline.
optional arguments:
-h, --help show this help message and exit
--conf FILE, -C FILE pipeline configuration file. (default: config.yaml)
--site SITE, -S SITE website to test; overrides config file (default: None)
--list LIST, -L LIST site list to test; overrides config file (default: None)
--from FROM, -F FROM the first entry to consider when a site list is provided; overrides config file (default: -1)
--to TO, -T TO the last entry to consider when a site list is provided; overrides config file (default: -1)
Configuración de entrada: JAW espera un archivo de configuración .yaml como entrada. Consulte config.yaml para ver un ejemplo.
Consejo. El archivo de configuración especifica diferentes pasos (por ejemplo, rastreo, análisis estático, etc.) que se pueden habilitar o deshabilitar para cada clase de vulnerabilidad. Esto permite ejecutar los bloques de construcción de la herramienta de forma individual o en un orden diferente (por ejemplo, rastrear todas las aplicaciones web primero, luego realizar el análisis de seguridad).
Para ejecutar un ejemplo rápido que demuestra cómo construir un grafo de propiedades y ejecutar consultas Cypher sobre él, haga:
$ python3 -m analyses.example.example_analysis --input=$(pwd)/data/test_program/test.js
Este módulo recopila los datos (es decir, código JavaScript y valores de estado de las páginas web) necesarios para las pruebas. Si desea probar un archivo JavaScript específico que ya tiene en su sistema de archivos, puede omitir este paso.
JAW tiene rastreadores basados en Selenium (JAW-v1), Puppeteer (JAW-v2, v3) y Playwright (JAW-v3). Para las características más actualizadas, se recomienda usar las versiones basadas en Puppeteer o Playwright.
Este rastreador web emplea foxhound, una versión instrumentada de Firefox, para realizar rastreo dinámico de manchas (taint tracking) mientras navega por las páginas web. Para iniciar el rastreador, haga:
$ cd crawler
$ node crawler-taint.js --seedurl=https://google.com --maxurls=100 --headless=true --foxhoundpath=<optional-foxhound-executable-path>
La foxhoundpath está establecida por defecto en el siguiente directorio: crawler/foxhound/firefox que contiene un binario llamado firefox.
Nota: necesita una compilación de foxhound para usar esta versión. En la versión JAW-v3 se incluye una compilación para Ubuntu.
Para iniciar el rastreador, haga:
$ cd crawler
$ node crawler.js --seedurl=https://google.com --maxurls=100 --browser=chrome --headless=true
Consulte aquí para más información.
Para iniciar el rastreador, haga:
$ cd crawler/hpg_crawler
$ vim docker-compose.yaml # configure aquí los sitios web que desea rastrear y guarde
$ docker-compose build
$ docker-compose up -d
Consulte la documentación de hpg_crawler aquí para más información.
Para generar un HPG para un (conjunto de) archivo(s) JavaScript, haga:
$ node engine/cli.js --lang=js --graphid=graph1 --input=/in/file1.js --input=/in/file2.js --output=$(pwd)/data/out/ --mode=csv
optional arguments:
--lang: language of the input program
--graphid: an identifier for the generated HPG
--input: path of the input program(s)
--output: path of the output HPG, must be i
--mode: determines the output format (csv or graphML)
Para importar un HPG dentro de una base de datos de grafos neo4j (instancia docker), haga:
$ python3 -m hpg_neo4j.hpg_import --rpath=<path-to-the-folder-of-the-csv-files> --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]
This script imports a CSV of a property graph into a neo4j docker database.
optional arguments:
-h, --help show this help message and exit
--rpath P relative path to the folder containing the graph CSV files inside the `data` directory
--id I an identifier for the graph or docker container
--nodes N the name of the nodes csv file (default: nodes.csv)
--edges E the name of the relations csv file (default: rels.csv)
Para crear un grafo de propiedades híbrido a partir de la salida de hpg_crawler e importarlo dentro de una instancia local de neo4j, también puede hacer:
$ python3 -m engine.api <path> --js=<program.js> --import=<bool> --hybrid=<bool> --reqs=<requests.out> --evts=<events.out> --cookies=<cookies.pkl> --html=<html_snapshot.html>
Especificación de parámetros:
<path>: ruta absoluta a la carpeta que contiene los archivos del programa para el análisis (debe estar bajo la carpeta engine/outputs).--js=<program.js>: nombre del programa JavaScript para el análisis (por defecto: js_program.js).--import=<bool>: si el grafo de propiedades construido debe importarse a una base de datos neo4j activa (por defecto: true).--hybrid=bool: si el modo híbrido está habilitado (por defecto: false). Esto implica que el evaluador desea enriquecer el grafo de propiedades proporcionando archivos para cualquiera de las instantáneas HTML, eventos disparados, peticiones HTTP y cookies, tal como los recopila el rastreador de JAW.--reqs=<requests.out>: solo para modo híbrido, nombre del archivo que contiene la secuencia de peticiones de red observadas; pase la cadena false para excluir (por defecto: request_logs_short.out).--evts=<events.out>: solo para modo híbrido, nombre del archivo que contiene la secuencia de eventos disparados; pase la cadena para excluir (por defecto: ).Para más información, puede usar la CLI de ayuda proporcionada con la API de construcción de grafos:
$ python3 -m engine.api -h
El HPG construido puede luego consultarse usando Cypher o el NeoModel ORM.
Debe colocar y ejecutar sus consultas en analyses/<ANALYSIS_NAME>.
Puede usar el NeoModel ORM para consultar el HPG. Para escribir una consulta:
example_query_orm.py en la carpeta analyses/example.$ python3 -m analyses.example.example_query_orm
Para más información, consulte aquí.
Puede usar Cypher para escribir consultas personalizadas. Para ello:
example_query_cypher.py en la carpeta analyses/example.$ python3 -m analyses.example.example_query_cypher
Para más información, consulte aquí.
Esta sección describe cómo configurar y usar JAW para la detección de vulnerabilidades, y cómo interpretar la salida. JAW contiene, entre otros, consultas autocontenidas para detectar CSRF del lado cliente y DOM Clobbering.
Paso 1. habilite el componente de análisis para la clase de vulnerabilidad en el archivo de entrada config.yaml:
request_hijacking:
enabled: true
# [...]
open_redirect:
enabled: false
# [...]
domclobbering:
enabled: false
# [...]
cs_csrf:
enabled: false
# [...]
Paso 2. Ejecute una instancia del pipeline con:
$ python3 -m run_pipeline --conf=config.yaml
Consejo. Puede ejecutar múltiples instancias del pipeline bajo diferentes screens:
$ 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'
$ # [...]
Para generar archivos de configuración paralelos automáticamente, puede usar el script generate_config.py.
Las salidas se almacenarán en un archivo llamado sink.flows.out en la misma carpeta que la entrada. Para CSRF del lado cliente, por ejemplo, para cada petición HTTP detectada, JAW genera una entrada que marca el conjunto de tipos semánticos (a.k.a., etiquetas semánticas o tags) asociados con los elementos que construyen la petición (es decir, los slices del programa). Por ejemplo, una petición HTTP marcada con el tipo semántico ['WIN.LOC'] es forjable a través del punto de inyección window.location. Sin embargo, una petición marcada con ['NON-REACH'] no es forjable.
A continuación se muestra un ejemplo de entrada de salida:
[*] 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
Esta entrada muestra que en la línea 29, hay una expresión de llamada $.ajax, y esta expresión de llamada desencadena una petición ajax con el valor de plantilla de url ajaxloc + "/bearer1234/", donde el parámetro ajaxloc es un slice del programa que lee su valor en la línea 6 de window.location.href, por lo tanto es forjable a través de ['WIN.LOC'].
Para agilizar el proceso de prueba de JAW y asegurarse de que su configuración sea correcta, proporcionamos una aplicación web simple en node.js con la que puede probar JAW.
Primero, instale las dependencias mediante:
$ cd tests/test-webapp
$ npm install
Luego, ejecute la aplicación en una nueva pantalla:
$ screen -dmS jawwebapp bash -c 'PORT=6789 npm run devstart; exec sh'
Para más información, visite nuestra página wiki aquí. A continuación, se muestra una tabla de contenido para acceso rápido.
Las solicitudes de extracción (pull requests) son siempre bienvenidas. Este proyecto pretende ser un espacio seguro y acogedor, y se espera que los contribuyentes se adhieran al código de conducta para contribuyentes.
Si utiliza JAW para investigación académica, le animamos a citar el siguiente artículo:
@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 ha recorrido un largo camino y queremos agradecer a nuestros contribuyentes de manera destacada aquí.
falseevents.out--cookies=<cookies.pkl>: solo para modo híbrido, nombre del archivo que contiene las cookies; pase la cadena false para excluir (por defecto: cookies.pkl).--html=<html_snapshot.html>: solo para modo híbrido, nombre del archivo que contiene la instantánea del árbol DOM; pase la cadena false para excluir (por defecto: html_rendered.html).