双查询注入
原理:
rand():随机函数
floor():取整函数
count():汇总函数
group by values:分组函数
当在一个聚合函数,比如count函数后面使用分组语句就会把查询的一部分以错误的形式显示出来;
先来看看子查询 select,就是在一个select语句中还含有一个select语句叫做子查询;
看个例子: Select concat ((select database()));
在查询的时候,子查询的select会把当前的数据库反馈给concat函数 (concat函数就是用来连接里面的结果)
1 | mysql> select rand(); |
接下来执行floor函数
1 | mysql> select floor(rand()*2); |
rand() 返回大于0小于1的小数,乘以2之后就成了小于0小于2了。然后对结果进行取整。就只能是0或1了。也就是这个查询的结果不是1,就是0
接下来进行测试
1 | mysql> select concat((select database()),floor(rand()*2)); |
SELECT database() 这个就返回数据库名,这里就是security了。然后FLOOR(RAND()*2)这个上面说过了。不是0,就是1.然后把这两个的结果进行concat连接,那么结果不是security0就是security1了。
接下来再加入group by 语句
1 | mysql> select count(*),concat((select database()),floor(rand()*2)) as test from |
我们把concat((select database()), floor(rand()*2)) 这个结果取了一个别名test ,然后使用他进行分组。这样相同的security0分到一组,security1分到一组。
这里的database()可以替换成任何你想查的函数,比如version(), user(), datadir()或者其他的查询。比如查表啊,查列啊。
最后再加上count(*)函数
1 | select count(*), concat((select database()), floor(rand()*2))as qqq from information_schema.tables group by qqq; |
count函数
count()是一个聚合函数,对于返回的结果集,一行行地判断,如果count函数的参数不是NULL,累计值就加1,否则不加。最后返回累计值。
*count(id)**
InnoDB引擎会遍历整张表,把每一行的id值都取出来,返回给server层。server层拿到id后,判断是不可能为空的,就按行累加。
count(1)
InnoDB引擎遍历整张表,但不取值。server层对于返回的每一行,放一个数字1进去,判断是不可能为空的,按行累加。
count(字段)
如果这个“字段”是定义为not null的话,一行行地从记录里面读出这个字段,判断不能为null,按行累加;如果这个字段定义允许为null,那么执行的时候,判断到有可能是null,还要把值取出来再判断一下,不是null才累加。
count(*)
不会把全部字段取出来,而是专门做了优化,不取值。count(*)肯定不是null,按行累加。
按照效率排序的话,count(字段)<count(主键id)<count(1)≈count(),所以建议尽量使用count()
count(id)虽然走的索引,但是还是需要一行一行的扫描才能统计出来总数,所以效率没有那么高。
注
*“通过floor报错的方法来爆数据的本质是group by语句的报错。group by语句报错的原因是floor(random(0)2)的不确定性,即可能为0也可能为1(group by key的原理是循环读取数据的每一行,将结果保存于临时表中。读取每一行的key时,如果key存在于临时表中,则不在临时表中则更新临时表中的数据;如果该key不存在于临时表中,则在临时表中插入key所在行的数据。group by floor(random(0)2)出错的原因是key是个随机数,检测临时表中key是否存在时计算了一下floor(random(0)2)可能为0,如果此时临时表只有key为1的行不存在key为0的行,那么数据库要将该条记录插入临时表,由于是随机数,插时又要计算一下随机值,此时floor(random(0)2)结果可能为1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值。具体原理参考:http://www.mysqlops.com/2012/05/15/mysql-sql-analyze.html)。”
结论是:当与临时表里面的值进行比较,如果不同,就插入,但是插入的时候又计算了一次,所以如果插入时计算的值与直接比较的值不一样,则报错!