SQL注入:floor报错注入的形成原理分析

SQL注入:floor报错注入的形成原理分析

我们知道在前端不回显查询结果时,可以尝试使用报错注入来将目标数据作为错误提示的一部分显示出来。

常见的报错注入有:利用updatexml()extractvalue()"floor报错",其中"floor报错"报错的原因相对比较复杂,本文将用图文和实机操作过程来分析它的原理。

一、涉及的函数(或语法)

“ floor报错注入 ”的原理相对复杂的一个原因是在构造这种注入时使用到的sql函数(或sql语法)很多,如rand()floor()concat()count(*)order by

(如果您对它们都比较了解的话,可以直接点此阅读本文的第二部分

1.rand()

rand()函数用于随机生成一个介于0~1之间的随机浮点数

请添加图片描述在这里插入图片描述

​ 可以看到,同样的语句,每一次执行会返回不同的值。(这里添加后面from users是为了能够多展示几个由rand()生成的连续随机数)

  • 可以向rand()中传入一个参数,来得到一个固定的随机数序列

在这里插入图片描述

但当向rand()中传入参数0,无论执行多少次,都会返回相同的结果,如上图。

2.floor()

floor意为“地板”,和它的字面意思一样,它可以实现对输入参数的向下取整(去除小数部分)
在这里插入图片描述

  • 如果我们将rand()floor()结合

    那么将永远得到0
    在这里插入图片描述

    ​ 如果我们将rand()乘以2,那么将永远得到0或1

    rand()得到一个零点几的数,(rand() * 2)得到一个零点几或一点几的数,经由floor()后自然得到一个0或1)
    在这里插入图片描述

3.concat()

一个用于拼接参数的函数

在这里插入图片描述

​ 这里使用concat()来将users表中的first_namelast_name使用-拼接了起来。

4.count()

一种聚合函数,用于统计“表”中个项出现的次数,count(*)会统计NULL

5.group by

根据by后面的“某种规则”来对数据进行筛选分组

  • group by常常配合聚合函数来使用,比如count()
    在这里插入图片描述

​ 这里的SQL语句从users表中查询出first_name列对应所有值,然后group by 后面的first_name为"分组依据",并使用count(*)来对该组中的各个项来计数,最终展现为如上图的查询结果。


二、报错原理

1.原理分析

使用group bycount(*)来得到表的过程,不是" 一蹴而就 "的

​ 而是先创建一个虚拟表,将查询到的各项一个个地作统计
在这里插入图片描述

​ 如下图,每接收到一个项,数据库都会判定虚拟表中是否有何该项值相等的组键(group_key),若没有则会重新"调用"一次该项并以调用结果创建一个新的组键,若已有则给该组键对应行的count(*)列加一。

在这里插入图片描述

到目前为止,好像还是没什么问题啊?

是的,如果写入虚拟表中的键名是“死的,不变化的普通字符串”,那么没有任何问题,如上述的users表中的first_name

​ 但如果这个项是“活的、变化的”呢?

​ 前面提到给rand()中输入参数会返回一个固定的连续随机数序列,那么floor(rand(0) * 2)将固定返回" 0、1、1、0,1…"
在这里插入图片描述

​ 那么concat(floor(rand(0)*2),0x7c,(select version()))就将返回"0|5.7.26"“1|5.7.26”“1|5.7.26”“1|5.7.26”“1|5.7.26”… (0x7c代表了 | 字符)

在这里插入图片描述

如果在补全虚拟表的时候,每一次调用我们的构造项(concat(floor(rand(0)*2),0x7c,(select version()))),它都会“向下“变化。

我们假设虚拟表中有且只有"1|5.7.26",这时刚好读取到的项是"0|5.7.26",因为虚拟表中没有组键"0|5.7.26",那么会重新调用该项并以调用结果创建新组键(但因为被重新调用,该项“向下”变化,变为了"1|5.7.26",所以虚拟表是为为"1|5.7.26"创建了新组键,而此时就会报错——试图创建重复(已存在)的组键"1|5.7.26")。

2.实例验证与分析

我们可以构造"payload"来验证我们所想:

select count(*), concat(floor(rand(0)*2),0x7c,(select version()))as alia from users group by alia;
(这里的as alia是为我们构造的长长的表达式concat(floor(rand(0)*2),0x7c,(select version()))起了别名alia

在这里插入图片描述

可以看到数据库的版本信息被连带进了报错信息。
具体的报错流程如下:

在这里插入图片描述

3.一个小挑战

以下有一个选项也可以达到floor(rand(0) * 2)一样的效果

您可以通过将它们的返回前几位固定数像上面一样带入“虚拟表”来判断是哪一个?

以此检测一下自己是否真的理解了floor报错注入相关的原理。

floor(rand(1) * 2)floor(rand(2) * 2)floor(rand(3) * 2)floor(rand(4) * 2)floor(rand(5) * 2)
01100
10011
01010
01100
00110
# 答案是...
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# .
# floor(rand(4) * 2),可以验证得知其余的构造均不可行(都会正常地创建拼接了0和1的对应组键)
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Neonline

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值