ukysblog
首页项目归档刷题记录照片墙音乐说说杂谈友链关于
封面

floor(rand(0)*2)的奥秘

2025-11-11 09:00:00
# sql

在sql报错注入中有一种floor()型的题,它通常以count(*),floor(rand(0)*2)...group by作为payload实现报错。那么它报错的具体原由是什么呢?
才没有在水博客🤫

在这之前,我们首先该理清这些mysql语法的作用

  • rand():从0-1之间随机返回一个浮点数,rand(value)则为rand定制了一个种子,使得rand返回为一个固定的伪随机数列。当这个函数被调用时,就会从这个数列里依次抽取返回值
  • count()...group by expr*:mysql的分组函数,这两个语句必须搭配在一起,group by* expr*负责根据后面的表达式的返回值作为gruop_key进行分组,而count负责对各组的数据进行计数
  • floor():向下取整,就是只舍不入

我们再详细讨论一下group by的分组逻辑

首先必须要注意的是一个组只能对应一个key值,这也是报错诱发原因

  1. 取得一条数据,根据表达式计算的返回值作为group_key,根据group_key检查它的组是否存在。如果之前存在相等的group_key,则分到对应的组
  2. 如果这个group_key是个新值,则以这个key值新建一个组,并把数据放在这个新组中。但要注意,在mysql插入新组之前还会再次计算一遍表达式的key值用来检查,然后用这个检查计算得到的key建立新组,这就是group by的双重调用

然后我们再详细解析为什么按floor(rand(0)*2)表达式分组会报错

从内而外,rand(0)定义了一个返回0-1的浮点数的伪随机数列,rand(0)*2使它的范围扩大到了0-2,而floor则使所有可能返回的浮点数向下取整为整数,使rand(0)*2变成只会返回0或1的固定数列。调用时会按照序列依次返回值

所以floor(rand(0)*2)其实是一组固定序列:

0 1 1 0 1 1...

我们再按照group by的逻辑分组:

  1. 取第一条记录,表达式返回为0,由于没有此类key值所以新建key,在建组之前进行检查,再次调用表达式,结果得到1,所以新建了一个key值为1的组
  2. 取第二条记录,表达式返回为1,已经有key为1的组了,所以分组成功,count++
  3. 第三条记录就出问题了,表达式先返回0,由于没有这个组,所以group by新建一个组,结果建组前检查再次调用了表达式使key变成了1,然后建立了一个key=1的新组,但第2步时已经建立了一个key=1的组,这就导致了两组key值冲突,不符合一组一值原则,进而引发了报错

这就是floor报错的缘由,不得不说发现这个报错方式的人简直是个天才,构造了如此精妙的payload

avatar

uky

后端安全方向,ctf-web手

RECOMMENDED

2025ISCTF-wp

2025-12-11 09:00:00

2026SHCTF-web阶段1/2

2026-2-14 09:00:00

带你体验第一视角手撕CC链

2026-5-14 21:10:00