在学习本实验之前,请确保已经学过“SQL注入原理与实践”这个实验。

在 SQL注入原理与实践 这个实验中,我们已经知道了SQL注入的原理,并且能够完成支持union 且有回显的注入,这种情况是最简单的,最容易注入的,那么,如果注入点发生在update、insert等这些不会有返回内容而仅仅只返回true或者false的 SQL语句中,或者仅仅select而没有输出查询的内容时,是不是就不能获取数据了呢?

当然不是,如果是这样,就不会有这个实验了,要想在上面所说的情况下获取数据,通过盲注就可以获取数据。

盲注主要应用在不能通过查询直接显示数据的地方,在盲注时,主要通过页面返回的不同来判断,盲注主要分为以下三种:

1.基于布尔的盲注。这种方法主要通过页面的返回内容不同来获取信息。

2.基于时间的盲注。这种方法主要通过页面的响应时间不同来获取信息。

3.基于报错的盲注。这种方法通过报错的方式把想要的信息爆出来。

下面就来学习上面三种盲注所用到的方法,首先看下基于布尔的盲注。

基于布尔的盲注主要通过页面的返回值不同来获取信息。并不是所有的页面都会输出SQL语句执行的错误,更常用的方法一般是用通用的错误信息来替代数据库错误信息,即使是出现通用的错误信息,我们也可以推断SQL注入是否可行。

它的判断原理是:如果我们注入的SQL指令被成功执行了,那么页面应该是正常显示而不是显示通用的错误信息,如果注入了SQL指令后,语句执行出错,那么页面就应该显示通用的错误信息而不是正常显示。

打开本次实验的测试页面:http://sqli.com/sqli-bool.php。

由于我们刚开始学MySQL盲注,所以先对着源码来进行注入,在以后的进阶、高阶实验中,将在不查看源码的情况下通过注入获取信息,源码保存在:C:\wamp\www\sqli目录下。查看sqli-bool.php源码如下:

可以看到,该页面输出仅有2种情况,sql语句执行成功输出“找到记录!”,失败则输出“没有找到记录!”,没有对查询后的内容进行输出,所以,我们不能像“SQL注入原理与实践”这个实验一样通过联合查询来获取数据,虽然像“SQL注入原理与实践”这个实验一样注入union指令可以执行成功,但是获取的数据,并没有返回给我们,所以,我们需要用其他办法来间接地获取数据。

基于布尔的盲注主要通过控制sql语句的where部分返回true或者false,以此来获取数据。所以我们需要通过在where 后面再添加一个条件,利用后面这个条件的正确与否来获取信息,比如,我们可以注入一个子查询,因为在数据库中子查询会先执行,它不会显示查询结果而是作为外部查询的条件,然后把这个子查询的结果跟某个字符或者字符串比较,如果返回true,则说明子查询的结果就是拿来比较的字符串,如果返回false,则说明子查询的结果就不是拿来比较的字符串,通过这种方式就可以获取数据。

如果我们要判断当前连接数据库是不是sqli,我们可以构造如下sql语句。

1 and (select database() = 'sqli')

此时数据库最终执行的是:

select * from `new` where id = 1 and (select database() = 'sqli') limit 0, 1

其中红色部分为我们注入的SQL指令。如果当前的数据库是sqli,则我们注入的子查询返回true,则相当于执行以下语句:

select * from `new` where id = 1 and (1) limit 0, 1

所以只要存在id=1的数据则这个查询会返回一条数据,页面输出“找到记录!”。很明显id=1的数据是存在的,所以此时的where 返回的是true。

注:在MySQL中,非空或者非0即为true,所以1就是true。

访问http://sqli.com/sqli-bool.php?id=1 and (select database() = 'sqli ')

输出“找到记录!”,然后把sqli改成其他字符。

输出“没有找到记录!”,说明当前连接的数据库就是sqli。

我们在没有输出信息的情况下就获取了当前的数据库。但是,如果数据库名比较长,很明显我们很难猜到,这样的话注入就会显得很鸡肋,因为要猜的次数太多了,即使数据库名长度为4,我们也需要列出所有长度为4的字母+数字的组合,然后一个一个来测试。这样无疑效率极低甚至数据库长度过长几乎数据库名都猜不到,更不用说获取里面的数据了。所以得再改进下。

实际上,在基于布尔型的盲注中,主要用到一些字符串函数,如:substring、ascii。利用这些函数来与指定的数字进行判断,以此来获取数据。

substring函数用来字符串截取,它的原型如下:

substring(str, pos, length),该函数最少需要2个参数,str为被截取字段,pos表示从第几位开始截取,length表示截取的长度,length可以不传参数,则表示从pos开始截取到字符串结束。例:

select substring(“abcdef”, 2) ,结果为:bcdef

select substring(“abcdef”, 2, 1),结果为 b

ascii函数用来求字符串的ascii码。例:

select ascii(‘a’),结果为97

利用这2个函数,我们对子查询的返回结果进行按位截取,然后获取对应的ascii码,最后跟我们指定的数字进行比较,如果这个ascii码跟我们指定的数字相等,则页面会输出“找到记录!”,否则输出“没有找到记录!”

所以,如果我们想要获取所有的数据库,可以先让子查询返回第一个数据库名,然后通过字符串截取分别截取每位后获取它的ascii码,最后来跟某个数字比较,我们只要依次增大该数字即可。

在“SQL注入原理与实践”这个实验中,已经讲解如何查询当前所有的数据库名,如果我们只获取一个数据库名,可以通过limit关键字来获取,如果给定limit一个参数,则表示返回多少条符合条件的数据,如果给2个函数,如: limit 1,1,则表示从结果中从偏移1开始获取1条记录。所以我们可以通过limit 来每次查询一个数据库的库名。

如图:

依次增大limit的第一个参数,即可获取所有的数据库名。

这里不再演示获取其他的数据库名,有兴趣的可以自己测试。

所以我们可以通过substring和ascii,可以更加简单地获取数据。

所以思路是这样的:首先子查询返回某个数据库名,然后通过substring函数来获取这个数据库名的第n个字符,然后计算它的ascii码,最后来跟某个数字比较,依次增加这个数字,使这2个数字相等。说明我们想要获取的字符的ascii码就是我们拿来比较的数字,然后根据ascii码求字符就行了。

为了减少一些不必要的工作,可以先判断一下数据库名、字段名以及列名的长度,比如,我们要查询第一个数据库库名的长度,可以构造如下语句:

sqli.com/sqli-bool.php?id=1 and length((select schema_name FROM information_schema.schemata LIMIT 0,1)) >10

如果第一个数据库名的长度大于10,则会输出“找到记录!”,如果小于10,则会输出“没有找到记录!”。

它的执行顺序为:

1.执行select schema_name from information_schema.schemata limit 0,1,这条SQL语句返回一条记录,也就是说,返回数据库中的一个数据库名,

2.然后length判断这个数据库名的长度,比如步骤一返回的结果为information_schema,那么就会执行length('information_schema'),这个函数执行以后的返回值为18。可能会觉得在上面构造的注入语句中,length没用单引号,但是在这里写了个单引号觉得疑惑,因为这里子查询返回结果为字符串,也就是说,子查询的返回结果传给length的时候,length会把传过去的返回值当作字符串,但是如果你自己在用length求某个字符串的时候,不用单引号,如:length(information_schema),就会提示语法错误,因为length只接受字符型参数。

3.length返回数据库名长度后, 会判断18 > 10的返回值,两个值比较的返回结果是布尔值,如果18 > 10成立,则返回true,否则返回false。而如果返回true,就会在数据库中查找id为1的记录,然后返回这条记录。如果返回false,则会没有记录返回。因为and 要求两边都返回true。

测试显示“找到记录!”说明第一个数据库名的长度大于10,然后把10逐渐增大,直接显示“没有找到记录! ,这里的大于号可以换成小于号或者等号,一般是先用大于号或者小于号通过二分法确定值在哪个区间,然后再用等号来确认具体的值。

由于这里url过长,浏览器没法完全显示,我们可以启用火狐的一个扩展:hackbar,在SQL注入的时候更加方便。启用方法:鼠标右击下图中红框中任意地方

然后选择 Hackbar即可启用。

如果需要停用Hackbar,用同样的方法取消勾选即可。

启用后界面如图:

此时下面的输入框就相当于浏览器的地址栏,输入完以后,可以点击左侧的execute即可。回车不会发出请求。

在测试的时候,可以一次增加5或者10,没必要每次只增加1。

测试到 = 18的时候,页面返回正常,说明第一个数据库名的长度为18。

然后就利用substring和ascii来获取这个数据库名。

判断它的第一个字符的ascii码是否大于64

http://sqli.com/sqli-bool.php?id=1 and ascii(substring((select schema_name FROM information_schema.schemata LIMIT 0,1),1,1)) >64

这里的执行顺序为:

1.首先执行里面的子查询

2.substring截取子查询的返回值的一个字符

3.利用ascii函数求substring截取的字符的ascii码

4.把64和ascii函数的返回值进行比较

5.根据比较后返回的布尔值来进行查询,如果步骤4返回false。则整个SQL语句返回结果为空。

提示“找到记录!”,说明第一个字符大于64。

这里为什么选择64呢?因为ascii码只有128个,64刚好是一半,我们用二分法,一次就可以排除掉一半。所以我们第二次应该是判断它是否大于 64+ 64/2。

依然正确。再次增加该值。

提示没有找到,所以可以确定,第一个字符的ascii码它位于96-115之间。继续修改该值,

我们还可以把大于号改成小于号或者等于号。

根据测试,数字等于 105的时候,输出“找到记录!”。

然后我们可以根据ascii码表来查或者通过程序来输出该ascii码对应的字母。查表可知字母i的ascii码为105,所以我们可以知道第一个数据库的第一个字符为“i”。

然后猜第二个字符。我们只需要把substring的第二个参数改成2,然后再依次把拿来比较的值改成64,重复上面的步骤。

该值为110的时候,输出找到记录!”。

可以确定第二个字符的ascii码为“110”,对应的字母为“n”。

如此重复,修改substring的第二个参数和比较的值,可以得知第一个数据库的库名。为:

information_schema。

如果要获取第二个数据库的库名,则修改limit的第一个参数为1,表示返回第二个数据库的库名。注:第一个数据库的库名偏移为0。

然后来获取第二个数据库库名,为了减少不必要的步骤,同样先来确定第二个数据库库名的长度。

第二个数据库库名的长度为5。然后重复上面步骤,获取数据库名的每一位,最后组合。

可以看到,第二个数据库名的第一个字符的ascii码为109。

第二个字符的ascii码为121。

如何重复以上步骤,可以获取所有的数据库名。

如果limit的第一个参数大于当前数据库数量的话,后面的数字就算小于31,也会提示“没有找到记录!“。

当前是limit 5,1 但是测试是否大于31的时候还是返回了false,说明没有偏移为5的数据库,也就是说,只有5个数据库,因为是从0开始算的。所以最多只能limit 4,1。那么为什么是31这个数字呢?

因为32以下的ascii码都是控制字符,不能显示。

最终获得的所有的数据库名:

information_schema

mysql

performance_schema

sqli

test

我们依然选择sqli为目标,先获取里面所有的表名。同样可以先判断第一个表名的长度。

长度为7。

第二个表名长度为3。

然后依次判断其他表名的长度。直到limit 3的时候,大于0都出错,说明这个数据库中只有3个表。

然后判断第一个表名的第一个字符的ascii码是否大于64。

http://sqli.com/sqli-bool.php?id=1 and ascii(substring((select table_name FROM information_schema.tables where table_schema='sqli' LIMIT 0,1),1,1)) > 64

提示“找到记录!“。

继续增加该值。等于109的时候正常。

然后获取第二个字符的ascii码,经过测试为101。

重复上述步骤可以得知第一个表名为:message。

然后获取第二个表名。首先获取第二个表名的第一个字符的ascii码。为110的时候正常。

继续修改substring的第二个参数,获取第二个字符的ascii码,为101。

重复上面的步骤,最终可以获取当前数据库中的3个表名,分别为:

message

new

user

同样选择获取user表中的数据。在这之前我们需要知道该表中有哪些列名。

猜测第一个列名的第一个字符的ascii码,为105

http://sqli.com/sqli-bool.php?id=1 and ascii(substring((select column_name FROM information_schema.columns where table_name='user' and table_schema='sqli' LIMIT 0,1),1,1)) =105

第二个字符的ascii 为 100。

当substring的第二个参数为3的时候,大于31也是返回错误,说明第一列只有2个字符,即:id。

然后获取第二列的列名。

第一个字符为u.

第二个为s

重复以上步骤,最终可以获得当前表中的所有列名:

id

username

password

lase_login

ip

知道了列名,就可以获取数据了。

比如我们要获取用户名,构造语句如下:

得知第一个用户名的第一个字符为“a”。

然后修改substring的第二个参数,获取第二个字符。

重复上面的步骤,可以得知第一个用户名为“admin”。

获取第二个用户名的第一个字符,为“z”。

第二个为“h”

重复上面步骤最终可以获取当前列中所有的用户名:

admin

zhangsan

lisi

wangwu

zhaoliu

可以用同样的方法获取其他表或者其他数据库中的数据。

至此,我们就在没有回显的情况下通过页面的返回值的不同获取了想要的数据。

mysql盲注_二十八、MySQL盲注相关推荐

  1. mysql revoke 用法_mysql进阶(二十八)MySQL GRANT REVOKE用法

    mysql进阶(二十八)MySQL GRANT REVOKE用法 MySQL的权限系统围绕着两个概念: 认证->确定用户是否允许连接数据库服务器: 授权->确定用户是否拥有足够的权限执行查 ...

  2. 燕十八 mysql 复习_燕十八 Mysql 笔记 68 课

    68 建表过程与字符类型的意义 目的:要学会建表 知识点:列类型 怎么建表? 以在 A4 纸上建表为例,表头写完就算表建好了,后面的是插入数据,建表的过程其实就是一个声明字段的过程 学号 姓名 家乡 ...

  3. 如何卸载mysql重新安装win10_学以致用二十八-----win10安装mysql5.7.24及卸载

    1.在windows环境下安装mysql,需要下载相对应的版本. ------------------------> 这里我下载的是mysql-5.7.24-win64.zip 2.下载后解压, ...

  4. mysql 变量作用域_二十二、MySQL基础系列笔记之变量

    什么MySQL变量 MySQL本质是一种编程语言,变量用来存储数据. 与所有语言一样,变量是用来存储数据的.我们平常所写的SQL语句,实际上是在SQL编程. MySQL两种变量 MySQL变量分为系统 ...

  5. MySQL二十八规范数据库设计

    MySQL二十八:规范数据库设计 糟糕的数据库设计: ●数据冗余,浪费空间 ●数据库插入和删除都会麻烦.异常[ 屏蔽使用物理外键] ●程序的性能差 良好的数据库设计: ●节省内存空间 ●保证数据库的完 ...

  6. 布尔教育mysql优化_布尔教育燕十八mysql优化视频课件源码分享

    目前数据库是大多数系统进行数据存储的基础组件,数据库的效率对系统的稳定和效率有着至关重要的影响:为了有更好的用户体验,数据库的优化显得异常重要.那么我们要从那些方面对我们的数据库进行优化呢?让我们在& ...

  7. 布尔教育mysql入门视频教程_布尔教育燕十八mysql入门视频教程的资源(源码课件)推荐...

    <布尔教育燕十八mysql入门视频教程>是mysql基础入门课程,随着mysql不断发展,现在使用mysql+php做网站已成为主流web开发技术,如果你想学习动态网页设计,那么建议你选择 ...

  8. 燕十八 mysql优化_布尔教育燕十八mysql优化视频资料分享

    目前数据库是大多数系统进行数据存储的基础组件,数据库的效率对系统的稳定和效率有着至关重要的影响:为了有更好的用户体验,数据库的优化显得异常重要.那么我们要从那些方面对我们的数据库进行优化呢?让我们在& ...

  9. Docker最全教程之MySQL容器化 (二十四)

    Docker最全教程之MySQL容器化 (二十四) 原文:Docker最全教程之MySQL容器化 (二十四) 前言 MySQL是目前最流行的开源的关系型数据库,MySQL的容器化之前有朋友投稿并且写过 ...

最新文章

  1. PyTorch 实现孪生网络识别面部相似度
  2. 网站应分析哪些方面来提升网站优化的效果呢?
  3. Erlang 的安装配置,编译和运行
  4. 实时流媒体编程基于Linux环境开发
  5. (转)使用JMeter进行Web压力测试
  6. redis 集群_Redis集群部署
  7. InfofoIE浏览器的好助手(转)
  8. 如何提取Excel中部分内容?
  9. A065_运行前端_跨域_列表_删除
  10. 你真以为贪吃蛇是个简单的游戏?
  11. 研究生发论文的流程?
  12. 对代码规范性的一点切实感受
  13. 第1天-代码随想录刷题训练| 704二分查找、26移除元素
  14. 18.3 KSM页面小结
  15. 结构体内存对齐,默认对齐数,结构体传参
  16. String s3 = quot;helquot; + new String(quot;loquot;);做了什么
  17. 通过360 软件管家,直接安装PinPKM V9.62
  18. 银行软件测试外包风险,软件测试外包存在哪些潜在的风险
  19. 计算机专业怎么学编程?
  20. 股票服务器系统,股票系统_ 《梦幻西游》电脑版官方网站 - 网易西游题材扛鼎之作...

热门文章

  1. 2020年Spring Cloud最后一个大版本发布!
  2. 就是你把所有代码全写在一个类里的?
  3. Edgware.RC1中ZuulFallbackProvider的改进
  4. python 异常分类_python的异常处理
  5. java es 5.0.1_es.5.1.1启动失败
  6. initMNN: init numpy failed mnn笔记
  7. numba.jit警告:failed type inference due to: non-precise type pyobject
  8. pytorch MaxUnpool2d
  9. tensorflow 查看graph
  10. pyinstaller 'utf-8' codec can't decode byte 0xce in position 123: invalid continuation byte