sql注入--双查询报错注入原理探索

目录

  • 双查询报错注入原理探索

    • part 1 场景复现
    • part 2 形成原因
    • part 3 报错原理
    • part 4 探索小结

双查询报错注入原理探索

上一篇讲了双查询报错查询注入,后又参考了一些博客,今天来探究其原理

实际上该报错是由于rand(),count(),group by 三个语句联合使用造成的,缺一不可。

上一篇的地址:https://www.cnblogs.com/laoxiajiadeyun/p/10278512.html

part 1 场景复现



首先我们新建一个数据库,并创建一个表用作实验:

mysql> CREATE DATABASE sql_test;
mysql> USE sql_test;
mysql> CREATE TABLE test(id int(2),name varchar(10));

接下来先插入一条数据测试:

mysql> INSERT INTO test VALUES("1","aaa");

下面看见已经插入了一条数据:

接下来我们构造一个报错条件,让其报错,显示出当前数据库名:

mysql> SELECT count(*),concat((SELECT database()),"~",floor(rand()*2))as a FROM test GROUP BY a;

查询的结果要么为sql_test~0,要么是sql_test~1,取决于随机数取整结果,不会触发报错。

接下来再在表中插入一条数据进行测试:

mysql> INSERT INTO test VALUES("2","bbb");

双查询语句与之前一样

运气很好,第一次就报错了,错误内容意思:group by 操作时主键 ‘sql_test~1’ 重复

还有其他正常执行不报错的情况:

可以看到,这里存在两条数据就可以引发报错,得到数据库信息。

part 2 形成原因



接下来我们再分析其报错的形成 原因:

先谈group by 函数:

在表中再插入两条数据,name值都为“bbb”:

mysql> INSERT INTO test VALUES("3","bbb");
mysql> INSERT INTO test VALUES("4","bbb");

成功后表如下:

这时候我们使用group by 语句时,MySQL会将查询结果分类汇总,重复的内容会合并为一项:

mysql> SELECT name FROM test GROUP BY name;

这时候再使用count()函数就可以对不同的条目计数:

mysql> SELECT count(*),name FROM test GROUP BY name;

如图:aaa有一条,bbb有3条

其背后的实现原理如下:

在执行group by name语句时,MySQL会在内部建立一个虚拟表,用来储存列的数据,表中会有一个group_key值作为表的主键,这里的主键就是用来分类的name列中获取,当查询数据时,取数据库数据,然后查看虚拟表中存在不,不存在则插入新记录

当读取到第一行数据时,aaa不存在,将aaa放入主键列中,1放在id列中

然后继续往下走,到了bbb,不存在,也放进去

往下执行,遇到多余的bbb,已经有bbb存在,就汇总在一起,内部情况如下:

如下,最后在查询的时候根据group by内部的实现方式返回分类后的结果:

当我们加上count(*)函数时,操作过程为:查看虚拟表存在不,不存在则插入新记录,存在则count(*)字段直接加1

这样就能对上面的分类结果进行统计,然后将统计结果返回:

所以双查询报错的关键就在这里,主要的原因在于rand()函数在group by的过程中被触发了多次,

part 3 报错原理



让我们回看一下构造的报错语句:

mysql> SELECT count(*),concat((SELECT database()),"~",floor(rand()*2))as a FROM test GROUP BY a;

执行前虚拟表为空:

当第一次执行时,group by 分组,其取的数据的是以a为别名的这条语句,假设这时的concat((SELECT database()),"~",floor(rand()*2))生成结果为sql_test~0,group就以sql_test~0查询虚拟表,发现表中没有该值的主键,于是将这条语句的结果插入到虚拟表中。

注意!是将这条语句的结果插入到虚拟表中,而不是将 sql_test~0 插入到虚拟表中,如下:

(将concat((SELECT database()),"~",floor(rand()*2)) 以a为别名,方便作图)

由于虚拟表没有内容,所以会将其插入到虚拟表中,这里的插入过程中,由于插入的是a语句的结果,所以在插入时a语句中的rand()函数会再次执行,即插入的值可能为sql_test~0 也可能为 sql_test~1 ,这里假设插入时a执行的结果为sql_test~0

所以上面的情况就是用sql_test~1这个结果查询虚拟表,不存在该数据,于是插入虚拟表,插入时又运算一次,然后插入的值变成了sql_test~0,所以这就是主要的冲突,表中只有一条数据还好,即使查询虚拟表的值和插入虚拟表的值不是同一个,但只有虚拟表也只生成一条记录,不会出现问题。

然而当表的数据出现两条以上的时候,第group by 在处理完第一条数据后会往下继续处理第二条,于是第二条还会按第一条的处理方式进行:

于是就会报错,报错内容如下:

ERROR 1062 (23000): Duplicate entry ‘sql_test~0‘ for key ‘group_key‘

如果第二次查询和插入的结果都一致:就会有下面两种情况:

  • 都是sql_test~0:表里已存在,该主键的count(*)值+1
  • 都是sql_test~1:表里没有,插入形成新的主键

part 4 探索小结



所以成因已经明白了:当group by 在查询虚拟表和插入虚拟表时,如果这两次a语句执行的结果不一致就会引发错误,错误提示信息是插入的主键重复,提示通过自定义报错信息中的主键值来获得敏感信息。

其中还可以通过修改rand()函数的随机因子,指定随机数生成方式来提高报错的效率,具体见深入分析的参考链接,这里不过多赘述。

希望这篇文章能给你带来帮助,如果文中有不正确的地方,还请私信或评论留言,我会仔细查看。

参考链接:



group by:https://blog.csdn.net/hao1066821456/article/details/69556644

双查询注入:https://www.cnblogs.com/BloodZero/p/4660971.html

http://www.lijiejie.com/mysql-injection-error-based-duplicate-entry/

Mysql报错注入原理分析:https://www.cnblogs.com/xdans/p/5412468.html#undefined

原文地址:https://www.cnblogs.com/laoxiajiadeyun/p/10283251.html

时间: 2024-12-28 15:47:07

sql注入--双查询报错注入原理探索的相关文章

sql盲注之报错注入(附自动化脚本)

作者:__LSA__ 0x00 概述 渗透的时候总会首先测试注入,sql注入可以说是web漏洞界的Boss了,稳居owasp第一位,普通的直接回显数据的注入现在几乎绝迹了,绝大多数都是盲注了,此文是盲注系列的第一篇,介绍盲注中的报错注入. 0×01 报错注入原理 其实报错注入有很多种,本文主要介绍几种常见的报错方法,有新姿势后续再更新. 1. Duplicate entry报错: 一句话概括就是多次查询插入重复键值导致count报错从而在报错信息中带入了敏感信息. 关键是查询时会建立临时表存储数

SQL报错注入总结

1.Floor()报错注入 关于Floor报错注入原理可以看http://blog.51cto.com/wt7315/1891458 获取数据库 select count(*),(concat(0x3a,database(),0x3a,floor(rand()*2))) name from information_schema.tables group by name; 获取表名 select count(*),concat(0x3a,0x3a,(select table_name from i

bypass 之报错注入

0x00 前言 前面讲到了bypass 联合查询和盲注,那么这章节就来个报错注入. 0x01 报错注入与函数 此方法是在页面没有显示位,但是echo mysql_error();函数输出了错误信息的时候方能使用.优点是注入速度快,缺点是语句较为复杂,而且只能用limit依次进行猜解.总体来说,报错注入其实是一种公式化的注入方法,主要用于在页面中没有显示位,但是用echo mysql_error();输出了错误信息时使用. 在联合查询查询能爆出数据是因为在页面有显示位,而盲注只能靠页面返回正常或者

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

0x00 疑问 一直在用mysql数据库报错注入方法,但为何会报错? 百度谷歌知乎了一番,发现大家都是把官网的结论发一下截图,然后执行sql语句证明一下结论,但是没有人去深入研究为什么rand不能和order by一起使用,也没彻底说明三者同时使用报错的原理. 0x01 位置问题? select count(*),(floor(rand(0)*2))x from information_schema.tables group by x; 这是网上最常见的语句,目前位置看到的网上sql注入教程,f

SQL报错注入结合sqli lab和百度杯CTF VId

0x00 背景 学习记录一下报错型的注入,经各方整理和自己总结形成. 所有的注入原理都是一样,即用户输入被拼接执行.但后台数据库执行语句产生错误并回显到页面时即可能存在报错注入. 0x01概念 报错型注入的利用大概有以下3种方式: 1:?id=2' and (select 1 from (select count(*),concat( floor(rand(0)*2),(select (select (查询语句)) from information_schema.tables limit 0,1

SQL报错注入的十余种注入方式

报错注入原理: 由于rand和group+by的冲突,即rand()是不可以作为order by的条件字段,同理也不可以为group by的条件字段. floor(rand(0)*2) 获取不确定又重复的值造成mysql的错误 floor:向下取整,只保留整数部分,rand(0) -> 0~1 本地环境搭建数据库测试注入姿势: mysql> create database sqli; mysql> create table user ( id int(11) not null auto_

i春秋——“百度杯”CTF比赛 十月场——Vld(Vulcan Logic Dumper 、php opcode、sql 报错注入)

打开题目看到提示 "do you know Vulcan Logic Dumper?" ,再查看源码看到"<!-- index.php.txt ?>",访问后发现一堆看不懂的东西 这肯定就是所谓的Vulcan Logic Dumper了,先了解下相关概念 PHP内核-Zend引擎:http://www.php.cn/php-weizijiaocheng-355597.html PHP中的opcode:https://blog.csdn.net/weiyu

SQL报错注入

0x00:前言 sqli-libs第11关的报错注入,之前没有具体学习了解过,所以单独学习一下. 0x01:例子 uname=1&passwd=1' union select count(*),concat(0x3a,0x3a,(select group_concat(schema_name) from information_schema.schemata),0x3a,0x3a,floor(rand(0)*2))a from information_schema.schemata group

SQL报错注入的12个函数及sql注入语句

转来的 侵删 1.通过floor报错,注入语句如下: and select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a); 2.通过ExtractValue报错,注入语句如下: and extractvalue(1, concat(0x5c, (select table_name from information_schema.tab