Mysql报错注入原理分析(count()、rand()、group by)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Mysql报错注入原理分析(count()、rand()、group by)


报错需要count(*)
,rand()、group by,三者缺一不可

前提:当行数大于等于3行时才会报错。


几个fool()原理解释:

https://www.cnblogs.com/xdans/p/5412468.html

https://www.cnblogs.com/litlife/p/8472323.html

http://www.cnblogs.com/xishaonian/p/6227405.html

select count(*),floor(rand(0)*2) from test group by floor(rand(0)*2)


首先看经典的floor注入语句:

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


第一眼看起来有些懵逼,我们来从最基本的入手,最后在分析这个语句


首先是floor()报错产生的条件:

select count(*) ,floor(rand(0)*2)x from security.users group by x(自定义数据库的一张表)


这里解释一下x是什么意思,可能有些同学不太熟悉sql语句,floor(rand(0)*2)x的x是为floor(rand(0)*2)添加了一个别名,就是x就等于floor(rand(0)*2),这样做的目的是

让group by 和 floor(rand(0)*2)相遇(请原谅我这么解释),


下一步我们在报错位置处加上我们想要的子查询,用concat()拼接:

select count(*) ,concat(database(),floor(rand(0)*2))x from security.users group by x


security就是我们想要的数据库名,1是上一步拼接的。


但现在是不是就可以直接使用了呢?还有几个步骤,先看直接拼接到and 后会怎样:

select * from security.users where id=1 and (select count(*) ,concat(database(),floor(rand(0)*2)x) from security.users group by x)


报了一个错,百度一番发现引发这个错误的原因很多,这里我是觉得我们构建的select语句的结果是一个结果表,而and 需要一个布尔值,也就是0或非零的值,那我们在嵌套一个查询,前面说了select 的结果是一个结果表,那我们就可再从这个表执行查询,只不过这次select的值是非零数字:


select 1 from (select count(*) ,concat(database(),floor(rand(0)*2))x from security.users group by x)a


再啰嗦一句,最后这个a和之前解释的x的作用是一样的,是前面括号内容的别名,

sql语句要求在查询结果的基础上再执行查询时,必须给定一个别名。

嵌套进and后执行


select * from security.users where id=1 and(select 1 from (select count(*) ,concat(database(),floor(rand(0)*2))x from security.users group by x)a)

大功告成

我们完成了刚开始引入的floo()注入语句

 

floor()报错注入

 

一 随机因子具有决定权(rand()和rand(0))


随机因子指的是rand(x) x是否有。


当插入一条记录时,不报错。

增加一条记录,有时候报错。

 

 

 


再增加一条记录也和2条记录一样进行随机报错。

三条及以上和2条记录一样进行随机报错。


分别对floor(rand()*2)和floor(rand(0)*2)在多记录表中执行多次(记录选择10条以上),在有12条记录表中执行结果如下图:


连续3次查询,毫无规则,接下来看看select floor(rand(0)*2) from T-Safe;,如下图:

可以看到floor(rand(0)*2)是有规律的,而且是固定的。


二 count与group by的虚拟表


在使用还有count() 和group by 的查询语句时,mysql在遇到select count(*) from TSafe group by x;这语句的时候到底做了哪些操作呢,我们果断猜测mysql遇到该语句时会建立一个虚拟表(实际上就是会建立虚拟表),那整个工作流程就会如下图所示:


1.先建立虚拟表,如下图(其中key是主键,不可重复):


2.开始查询数据,取数据库数据,然后查看虚拟表存在不,不存在则插入新记录,存在则count(*)字段直接加1,如下图:

由此看到 如果key存在的话就+1, 不存在的话就新建一个key。


三 floor(rand(0)*2)报错


1.查询的时候如果使用rand()的话,该值会被计算多次,就是在使用group by的时候,floor(rand(0)*2)会被执行一次,如果虚表不存在记录,插入虚表的时候会再被执行一次,以此类推。

           

 注:使用group by,即虚表存储是按照group by 计算的那一列来从上往下来

计算,取一条记录判断虚表是否存在时会使函数执行一遍,当存入的时候(即表中key值无此值)会将原函数存入,但是存的内容是最终结果,即原函数会被再次执行结果存入虚表,当表中有此键值对,那么只需count+1,不用再存key,所以比较时会计算一次,存入时又会计算一次


2.在使用count(*)时,如

     select count(*) from test group by x;  x=floor(rand(0)*2)

               mysql执行此句时会创建一个虚表,虚表一共两个字段主键是x,另外一个字段是count(*)


3.首先知道floor(rand(0)*2)的值为011011...,


4.执行的过程floor(rand(0)*2)报错的原因):(插入之前是表面显示数据,实际比较时和存储时为表面数据计算之后的结果,这取决于数据库的一种存储机制,表面的sql语句会被审查,然后执行存入数据库,再回显数据库中存的内容,即结果)

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

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

           (这个位置的floor(..))有没有无所谓用不到

 

 1).查询前默认会建立空虚拟表如下图:

  

 

 

  

2).开始执行,查询第一条记录(即数据),在使用group by时 floor(rand(0)*2)执行一次,结果为0,即x=0(第一次执行),然后发现虚表中没有key=0的键值对记录,则floor(rand(0)*2)会被存入虚表,存入时会被计算为实际的值,即会被再执行一次(第二次执行),结果为1插入虚表,同时count由0变1。

  

 

 

 

 3)取第二条记录,floor(rand(0)*2)执行一次,结果为1(第三次执行),查询虚表,发现虚表中有1,则直接count+1,不用再存key,所以floor(rand(0)*2)不会再被计算。

  

4).取第三条记录,floor(rand(0)*2)执行一次,结果为0,发现虚表中没有key=0,那么floor(rand(0)*2)会再次执行并存入虚表,此次计算结果为1(第五次执行),与已有的key冲突了,所以插入时报错。

     

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


四 floor(rand()*2)报错


由此我们可以同样推理出不加入随机因子的情况,由于没加入随机因子,所以floor(rand()*2)是不可测的,因此在两条数据的时候,只要出现下面情况,即可报错,如

下图:


最重要的是前面几条记录查询后不能让虚表存在0,1键值,如果存在了,那无论多少条记录,也都没办法报错,因为floor(rand()*2)不会再被计算做为虚表的键值,这也就是为什么不加随机因子有时候会报错,有时候不会报错的原因。如图:


当前面记录让虚表长成这样子后,由于不管查询多少条记录,floor(rand()2)的值在虚表中都能找到,所以不会被再次计算,只是简单的增加count()字段的数量,所以不会报错,比如floor(rand(1)*2),如图:


 

 

在前两条记录查询后,虚拟表已经存在01两个键值了,所以后面再怎么弄还是不会报错。


总之报错需要count(*),rand()、group by,三者缺一不可


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
24天前
|
NoSQL 关系型数据库 MySQL
2024Mysql And Redis基础与进阶操作系列(4-2)作者——LJS[含MySQL非空、唯一性、PRIMARY KEY、自增列/自增约束举例说明等详解步骤及常见报错问题对应的解决方法]
24MySQL非空、唯一性、PRIMARY KEY、自增列/自增约束举例说明等详解步骤及常见报错问题对应的解决方法(4-2) 学不会你来砍我!!!
|
24天前
|
NoSQL 安全 关系型数据库
2024Mysql And Redis基础与进阶操作系列(6)作者——LJS[含MySQL 多表之一对一/多;多对多;多表联合查询等详解步骤及常见报错问题所对应的解决方法]
MySQL 多表之一对一/多;多对多;多表联合之交叉连接;内连接;左、右、外、满、连接;子查询及关键字;自连接查询等详解步骤及常见报错问题所对应的解决方法
|
24天前
|
SQL NoSQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(5)作者——LJS[含MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页等详解步骤及常见报错问题所对应的解决方法]
MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页、INSERT INTO SELECT / FROM查询结合精例等详解步骤及常见报错问题所对应的解决方法
|
24天前
|
SQL NoSQL 关系型数据库
|
25天前
|
存储 SQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(1)作者——LJS[含MySQL的下载、安装、配置详解步骤及报错对应解决方法]
Mysql And Redis基础与进阶操作系列(1)之[MySQL的下载、安装、配置详解步骤及报错对应解决方法]
|
24天前
|
SQL 关系型数据库 MySQL
|
24天前
|
存储 SQL NoSQL
|
1月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1643 14
|
1月前
|
存储 关系型数据库 MySQL
基于案例分析 MySQL 权限认证中的具体优先原则
【10月更文挑战第26天】本文通过具体案例分析了MySQL权限认证中的优先原则,包括全局权限、数据库级别权限和表级别权限的设置与优先级。全局权限优先于数据库级别权限,后者又优先于表级别权限。在权限冲突时,更严格的权限将被优先执行,确保数据库的安全性与资源合理分配。
|
24天前
|
NoSQL 关系型数据库 MySQL
2024Mysql And Redis基础与进阶操作系列(8)作者——LJS[含MySQL 创建、修改、跟新、重命名、删除视图等具体详步骤;注意点及常见报错问题所对应的解决方法]
MySQL 创建、修改、跟新、重命名、删除视图等具体详步骤;举例说明注意点及常见报错问题所对应的解决方法
下一篇
无影云桌面