
Un fuzzer guidé par mutation pour les pare-feu d'applications Web basés sur l'apprentissage automatique
Un fuzzer guidé par mutations pour les pare-feu d'applications web (WAF) basés sur l'apprentissage automatique, inspiré par AFL et basé sur le FuzzingBook d'Andreas Zeller et al.
Étant donnée une requête d'injection SQL, il tente de produire une requête sémantiquement invariante capable de contourner le WAF cible. Vous pouvez utiliser cet outil pour évaluer la robustesse de votre produit en laissant WAF-A-MoLE explorer l'espace des solutions pour trouver les « angles morts » dangereux laissés par le classifieur cible.

WAF-A-MoLE prend une charge utile initiale et l'insère dans le Pool de charges utiles, qui gère une file de priorité ordonnée par le score de confiance du WAF pour chaque charge utile.
Lors de chaque itération, la tête du Pool de charges utiles est transmise au Fuzzer, où elle est mutée aléatoirement en appliquant l'un des opérateurs de mutation disponibles.
Les opérateurs de mutation sont tous préservant la sémantique et exploitent la grande expressivité du langage SQL (dans cette version, MySQL).
Voici les opérateurs de mutation disponibles dans la version actuelle de WAF-A-MoLE.
WAF-A-MoLE implémente la méthodologie présentée dans "WAF-A-MoLE: Evading Web Application Firewalls through Adversarial Machine Learning". Une prépublication de notre article est également disponible sur arXiv.
Si vous souhaitez nous citer, veuillez utiliser la référence (BibTeX) suivante :
@inproceedings{demetrio20wafamole,
title={WAF-A-MoLE: evading web application firewalls through adversarial machine learning},
author={Demetrio, Luca and Valenza, Andrea and Costa, Gabriele and Lagorio, Giovanni},
booktitle={Proceedings of the 35th Annual ACM Symposium on Applied Computing},
pages={1745--1752},
year={2020}
}
pip install -r requirements.txt
Vous pouvez évaluer la robustesse de votre propre WAF, ou essayer WAF-A-MoLE contre quelques classifieurs d'exemple. Dans le premier cas, jetez un œil à la classe Model. Votre modèle personnalisé doit implémenter cette classe pour être évalué par WAF-A-MoLE. Nous fournissons déjà des adaptateurs pour les classifieurs sci-kit learn et keras qui peuvent être étendus pour s'adapter à votre phase d'extraction de caractéristiques (si elle existe).
wafamole --help
Usage: wafamole [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
evade Launch WAF-A-MoLE against a target classifier.
wafamole evade --help
Usage: wafamole evade [OPTIONS] MODEL_PATH PAYLOAD
Launch WAF-A-MoLE against a target classifier.
Options:
-T, --model-type TEXT Type of classifier to load
-t, --timeout INTEGER Timeout when evading the model
-r, --max-rounds INTEGER Maximum number of fuzzing rounds
-s, --round-size INTEGER Fuzzing step size for each round (parallel fuzzing
steps)
--threshold FLOAT Classification threshold of the target WAF [0.5]
--random-engine TEXT Use random transformations instead of evolution
engine. Set the number of trials
--output-path TEXT Location were to save the results of the random
engine. NOT USED WITH REGULAR EVOLUTION ENGINE
--help Show this message and exit.
Nous fournissons quelques modèles pré-entraînés avec lesquels vous pouvez vous amuser, situés dans wafamole/models/custom/example_models. Les classifieurs que nous avons utilisés sont listés dans le tableau ci-dessous.
En plus du WAF basé sur l'apprentissage automatique, WAF-a-MoLE supporte également les WAF basés sur des règles. Plus précisément, il fournit un adaptateur pour le WAF ModSecurity équipé du OWASP Core Rule Set (CRS), basé sur le projet pymodsecurity.
Contourner le classifieur WAF-Brain pré-entraîné en utilisant un équivalent de admin' OR 1=1#.
wafamole evade --model-type waf-brain wafamole/models/custom/example_models/waf-brain.h5 "admin' OR 1=1#"
Contourner le classifieur SVM ML-Based-WAF pré-entraîné en utilisant un équivalent de admin' OR 1=1#.
wafamole evade --model-type mlbasedwaf wafamole/models/custom/example_models/mlbasedwaf_svc.dump "admin' OR 1=1#"
Contourner le classifieur SVM ML-Based-WAF pré-entraîné en utilisant un équivalent de admin' OR 1=1#. Notez que SQLiV5 est un jeu de données provenant de Kaggle enrichi avec une série de requêtes générées par WAF-A-MoLE elle-même, comme preuve de concept que les requêtes de WAF-A-MoLE peuvent améliorer la robustesse d'un WAF grâce au réentraînement. Utilisez mlbasedwaf_svc_sqliv3.dump pour contourner le WAF entraîné avec le jeu de données Kaggle original (SQLiV3).
wafamole evade --model-type mlbasedwaf wafamole/models/custom/example_models/mlbasedwaf_svc_sqliv5.dump "admin' OR 1=1#"
Contourner le classifieur SGD ML-Based-WAF pré-entraîné en utilisant un équivalent de admin' OR 1=1#.
wafamole evade --model-type mlbasedwaf wafamole/models/custom/example_models/mlbasedwaf_sgd.dump "admin' OR 1=1#"
Contourner le classifieur AdaBoost ML-Based-WAF pré-entraîné en utilisant un équivalent de admin' OR 1=1# (prend plus de temps que les autres modèles, environ 2 à 5 minutes d'exécution).
wafamole evade --model-type mlbasedwaf wafamole/models/custom/example_models/mlbasedwaf_ada.dump "admin' OR 1=1#"
Contourner le classifieur Naive Bayes basé sur les jetons pré-entraîné en utilisant un équivalent de admin' OR 1=1#.
wafamole evade --model-type token wafamole/models/custom/example_models/naive_bayes_trained.dump "admin' OR 1=1#"
Contourner le classifieur Forêt aléatoire basé sur les jetons pré-entraîné en utilisant un équivalent de admin' OR 1=1#.
wafamole evade --model-type token wafamole/models/custom/example_models/random_forest_trained.dump "admin' OR 1=1#"
Contourner le classifieur SVM linéaire basé sur les jetons pré-entraîné en utilisant un équivalent de admin' OR 1=1#.
wafamole evade --model-type token wafamole/models/custom/example_models/lin_svm_trained.dump "admin' OR 1=1#"
Contourner le classifieur SVM gaussien basé sur les jetons pré-entraîné en utilisant un équivalent de admin' OR 1=1#.
wafamole evade --model-type token wafamole/models/custom/example_models/gauss_svm_trained.dump "admin' OR 1=1#"
Contourner le classifieur SQLiGOT pré-entraîné en utilisant un équivalent de admin' OR 1=1#.
Utilisez DP, UP, DU, ou UU pour (respectivement) Proportionnel Dirigé, Proportionnel Non Dirigé, Non Proportionnel Dirigé et Non Proportionnel Non Dirigé.
wafamole evade --model-type DP wafamole/models/custom/example_models/graph_directed_proportional_sqligot "admin' OR 1=1#"
Contourner l'OWASP ModSecurity CRS en utilisant un équivalent de admin' OR 1=1#.
L'utilisateur doit également spécifier le Niveau de Paranoïa ainsi que le chemin pour localiser les règles CRS (par exemple, /etc/coreruleset).
wafamole evade --model-type modsecurity_pl[1-4] /etc/coreruleset "admin' OR 1=1#"
AVANT DE LANCER L'ÉVALUATION SUR SQLiGoT
Ces classifieurs sont plus robustes que les autres, car la phase d'extraction de caractéristiques produit des vecteurs avec une structure plus complexe, et tous les classifieurs pré-entraînés ont été fortement régularisés. Il peut falloir des heures pour que certaines variantes produisent une charge utile qui atteigne le contournement (voir la section Benchmark).
Note sur les modèles ML-Based-WAF plus récents
Certains modèles basés sur une version légèrement modifiée de ML-Based-WAF de vladan-stojnic ont été récemment ajoutés, provenant d'une extension de WAF-A-MoLE intitulée wafamole++ par nidnogg. Tester le modèle AdaBoost peut prendre plus de temps que d'habitude (généralement 2 à 5 minutes).
Il existe des variantes entraînées avec le jeu de données SQLiV5.json, tandis que la plupart utilisent l'injection SQL originale du jeu de données WAF-A-MoLE par défaut.
Un notebook Google Colaboratory est fourni avec les routines d'entraînement pour certains de ces modèles, utilisant le jeu de données original WAF-A-MoLE (modifié au format SQLiV5). Tout jeu de données peut être utilisé à condition qu'il soit dans le même format que SQLiV5.json.
Tout d'abord, créez une classe Model personnalisée qui implémente les méthodes extract_features et classify.
class YourCustomModel(Model):
def extract_features(self, value: str):
# TODO: extraire les caractéristiques
feature_vector = your_custom_feature_function(value)
return feature_vector
def classify(self, value):
# TODO: calculer la confiance
confidence = your_confidence_eval(value)
return confidence
Ensuite, créez un objet à partir du modèle et instanciez un objet engine qui utilise votre classe de modèle.
model = YourCustomModel() #votre init
engine = EvasionEngine(model)
result = engine.evaluate(payload, max_rounds, round_size, timeout, threshold)
Nous avons évalué WAF-A-MoLE contre tous nos modèles d'exemple.
Le graphique ci-dessous montre le temps qu'il a fallu à WAF-A-MoLE pour muter la charge utile admin' OR 1=1# jusqu'à ce qu'elle soit acceptée comme bénigne par chaque classifieur.
Sur l'axe des x, nous avons le temps (en secondes, échelle logarithmique). Sur l'axe des y, nous avons la valeur de confiance, c'est-à-dire la certitude d'un classifieur qu'une charge utile donnée est une injection SQL (en pourcentage).
Notez qu'être « sûr à 50% » qu'une charge utile est une injection SQL équivaut à lancer une pièce de monnaie. C'est le seuil de classification habituel : si la confiance est inférieure, la charge utile est classée comme bénigne.

Les expériences ont été réalisées sur des DigitalOcean Standard Droplets.
Les questions, rapports de bogues et demandes d'extraction sont les bienvenus.
En particulier, si vous souhaitez contribuer à ce projet, nous recherchons les contributions suivantes :
| Mutation | Exemple |
|---|
| Changement de casse | admin' OR 1=1# ⇒ admin' oR 1=1# |
| Substitution d'espaces blancs | admin' OR 1=1# ⇒ admin'\t\rOR\n1=1# |
| Injection de commentaire | admin' OR 1=1# ⇒ admin'/**/OR 1=1# |
| Réécriture de commentaire | admin'/**/OR 1=1# ⇒ admin'/*xyz*/OR 1=1#abc |
| Encodage d'entier | admin' OR 1=1# ⇒ admin' OR 0x1=(SELECT 1)# |
| Échange d'opérateur | admin' OR 1=1# ⇒ admin' OR 1 LIKE 1# |
| Invariant logique | admin' OR 1=1# ⇒ admin' OR 1=1 AND 0<1# |
| Mélange de nombres | admin' OR 1=1# ⇒ admin' OR 2=2# |
| Nom du classifieur | Algorithme |
|---|
| WafBrain | Réseau de neurones récurrents |
| ML-Based-WAF | SVM non linéaire |
| ML-Based-WAF | Descente de gradient stochastique |
| ML-Based-WAF | AdaBoost |
| Basé sur les jetons | Naive Bayes |
| Basé sur les jetons | Forêt aléatoire |
| Basé sur les jetons | SVM linéaire |
| Basé sur les jetons | SVM gaussien |
| SQLiGoT - Proportionnel dirigé | SVM gaussien |
| SQLiGoT - Non proportionnel dirigé | SVM gaussien |
| SQLiGoT - Proportionnel non dirigé | SVM gaussien |
| SQLiGoT - Non proportionnel non dirigé | SVM gaussien |