分享

SQL报错型盲注教程(原理全剖析)

 quasiceo 2018-08-17

一、前言

在学习了普通的SQL注入,普通的盲注后,进入到报错型的盲注学习

本教程基于sqli-labs的level 5进行实验

二、正文

报错型盲注

众所周知,盲注并不会返回错误信息,使得sql注入的难度提高。而报错型注入则是利用了MySQL的第8652号bug :Bug #8652 group by part of rand() returns duplicate key error来进行的盲注,使得MySQL由于函数的特性返回错误信息,进而我们可以显示我们想要的信息,从而达到注入的效果;当然其他类型的数据库也存在相应的问题,在此我们不提。

原理剖析

Bug 8652的主要内容就是在使用group by 对一些rand()函数进行操作时会返回duplicate key 错误,而这个错误将会披露关键信息,如

"Duplicate entry '####' for key 1"
这里的####正是用户输入的希望查询的内容

而该bug产生的主要原因就是:在rand()和group by同时使用到的时候,可能会产生超出预期的结果,因为会多次对同一列进行查询


对这个bug的利用

显然,我们需要巧妙地构造出能够触发上面这种类型报错的语法,或者说是公式来有意地触发bug。

网上已经有一些这方面的“公式”存在了,我们来看看这个公式到底是如何运行的?在这里我们使用sqli-labs的level 5作为公式例子讲解

?id=1' union Select 1,count(*),concat(你希望的查询语句,floor(rand(0)*2))a from information_schema.columns group by a--+

经过测试我们知道select的字段数为3,因此这里需要用select a,b,c……

a)函数说明

      count()统计原组的个数


      concat  字符串连接


      floor  向下取整


      rand()  产生一个0~1的随机数


      rand(0),rand(1),当使用一个整数参数时,rand使用该参数作为种子生成一个固定的伪随机数列

c)

通过下面的例子我们可以发现rand()产生伪随机数列,而rand()使用了参数后则会产生固定的伪随机数列

可以发现,rand()产生不固定的伪随机数列

而rand加了参数之后则会产生固定的伪随机数列


b)分析原理

我们再次把公式传送到这里方便我们进行分析

?id=1' union Select 1,count(*),concat(你希望的查询语句,floor(rand(0)*2))a from information_schema.columns group by a

首先,我观察到,使用rand()有可能报错有可能不报错。

分析原因:rand()产生伪随机数列,因此每次结果不同,根据不同的结果会产生报错或不报错:即rand产生的数列是报不报错的关键!!!!!

于是,对rand(0),rand(1),rand(2),rand(3),rand(4),rand(5),rand(6)的循环数列进行分析,在这里就不贴过多的图了,rand(0)上图,其他直接po数列

注:这里所说的rand()都是floor(rand())取整后的结果


rand(0):0110110011

rand(1):0100011000

rand(2):1011001001

rand(3):1001100110

rand(4):0110111111

rand(5):0100011100

rand(6):1011100000

rand(7):1001100001

rand(8):0110011010

rand(9):0100110111

rand(10):1011100100

rand(11):1001001101

经过测试,rand(0),rand(4),rand(11)会报错,而其他不会,我们还可以发现rand(8)前面的结构跟rand(0),rand(4)几乎一样,在测试前我曾以为他会报错,没想到竟然没报错,因此我才一路测试到了rand(11),以求发现报错的奥秘,因此接下来我们对0,4,8,11的数列进行对比分析

可以看到,其实在前六个数字里,rand0和rand4的值是一模一样的,后面就不相同了,因此我们判定前六个数字的某种关系使得rand0和rand4报错

对于rand8,他的前六个数字只有一个数字与rand0,rand4不同,因此,我们也可以判定,它不报错的原因就是因为第5个数字不同

样例公式:?id=1' union Select 1,count(*),concat(你希望的查询语句,floor(rand(0)*2))a from information_schema.columns group by a--

——这里插入一个小知识:在进行查询时,sql会根据需要建立临时表进行数据的存储

关于为什么会报错,上面po出的官方介绍中说到,对同一列进行多次查询,即rand多次执行,那么我们可以猜测,当查询第一条语句时,结果为0,可以知道在临时表中键值为0不存在,因此我们会进行插入结果的操作,在插入之前猜测rand再次执行,因此插入了键值为1的结果

下一个数:此时已经查询到了第三个数“1”,因为临时表已存在该数,因此count值+1

下一个数:此时查询到0,又因为不存在该值,因此我们又会进行插入结果的操作,继续我们的猜测,在插入前进行rand的再次执行,因此想要插入值为1的新列,而值为1的列已存在,因此报错(count()函数的特性)!

=>推出我们的猜测:在执行插入操作前,rand()会再次执行

对rand0,rand4进行验证,发现没有问题!

对于rand8,因为第五个字母为0,因此在进行插入时,插入的新列的键值为0,因此不存在列重复的问题,因此不报错!!

接下来我们对rand11进行验证

第一次查询:1,检测到键值为1的列不存在,想要插入新列,再次进行查询,插入了键值为“0”的列

第二次查询:0,检测到已存在,count++

第三次查询:1,检测到键值为1的列不存在,想要插入新列,再次进行查询,插入了键值为“0”的列,又因为该列已存在,故报错!!

验证成功!,理论暂且可行!由于MySQL的帮助文档没有指明到底会如何多次进行查询,因此我们姑且可以这样认为在插入之前猜测rand再次执行是其中的一个逻辑判定


我们还可以得出这样的推论:

对于一个整数x,对于floor(rand(x)*2)产生的序列,如果在未出现“0011”或“1100”序列前出现“0010“或”1101”,那么该floor(rand(x)*2)产生的序列可用于报错型sql盲注

实战演练

sqli-labs level5

首先判断查询语句的形式,也就是单引号测试法,双引号测试法,加括号等等进行测试,这里就不展示了

测试来是字符型的普通单引号注入

0x00利用盲注技术判断查询字段数

得到查询字段数为三,接着我们套公式进行相应内容的爆破

0x01爆数据库名

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' union Select 1,count(*),concat(0x23,0x23,(select database()),0x23,0x23,floor(rand(0)*2))a from information_schema.columns group by a--+


0x02爆表名

首先查询一下表的个数

http://127.0.0.1/sqli-labs-master/Less-5/?id=1' union Select 1,count(*),concat(0x23,0x23,(select count(table_name) from information_schema.tables where table_schema='security' limit 0,1),0x23,0x23,floor(rand(0)*2))a from information_schema.columns group by a--+    注:这里的limit可有可无

可以看到,表的个数有6个

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多