mysql盲注_二十八、MySQL盲注

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

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

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

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

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

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

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

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

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

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

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

ffcb27752f372b1104cdf3dc2a123694.png

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

c532d4168cf3ed676a52dd4207204636.png

可以看到,该页面输出仅有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 ')

c003cd5cb704e7b741064b89a0fd5208.png

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

da959e58b7d3432e97a872da1b044a3e.png

输出“没有找到记录!”,说明当前连接的数据库就是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 来每次查询一个数据库的库名。

如图:

e5326e0e51071e5b0a98406ad5cc3fa6.png

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

cf095075bd3f730f3d89409c191ab77d.png

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

所以我们可以通过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逐渐增大,直接显示“没有找到记录! ,这里的大于号可以换成小于号或者等号,一般是先用大于号或者小于号通过二分法确定值在哪个区间,然后再用等号来确认具体的值。

4923f7c2f35ddda1fcaca2ef4cd0f8b4.png

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

7fae56d66644406181eecd0e201f5594.png

然后选择 Hackbar即可启用。

4a6a13bde2d5c36833e3b1244d60608d.png

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

启用后界面如图:

e8afdae4b4fca6124b426c9340067aec.png

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

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

23ba0dc6e16974aefd9cf0d1671c1c2d.png

测试到 = 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

c38a5b05de92ab1f09de9f5e86659288.png

这里的执行顺序为:

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

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

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

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

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

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

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

6450350ba60b6f0155d7f1961ec8fd44.png

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

6d686b26e92e0563e4d4513cf9fb1eff.png

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

9e6b14e079d9501fdabcd32f9afff8a1.png

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

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

f2a5038aad6f253a88e083a5bee41fee.png

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

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

f2959cd48644722fe035450a0429aee6.png

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

a4260b8db6b232738b365ed3742f72d6.png

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

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

information_schema。

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

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

511c1444c82718f7a147b813f0111a02.png

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

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

06e29ad9bab474c60a0ff4504fa760a9.png

第二个字符的ascii码为121。

4aef3ad990485cdd433c76c4e93eb23b.png

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

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

9dfea38cbfe7ea4dd7ad050c89a8e2fa.png

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

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

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

information_schema

mysql

performance_schema

sqli

test

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

b8bf9ae98d1559ce97b87d0c320b8c3c.png

长度为7。

b007db62a9394e5018387e9aadb0f76c.png

第二个表名长度为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

提示“找到记录!“。

3b94e779f465ccfad6133b31b4600074.png

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

66021b45de3c6ff586543915a0187b3b.png

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

e1d66eb1e5c2685c948b5aae04e91d9f.png

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

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

5be9b56df3504cf969331456ee01bec4.png

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

5fe8095f97d699aa7e83a37db8358ba1.png

重复上面的步骤,最终可以获取当前数据库中的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

0c04df2175f59de33177957603c489a2.png

第二个字符的ascii 为 100。

8fc00cacc556c4f072f01162f5e70dac.png

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

04109c40b25ff207982ea3e7d0e99197.png

然后获取第二列的列名。

第一个字符为u.

ae7a6f020cf79ca063bc6fe9036e8589.png

第二个为s

ecbc0c0c5d6f5e0669dacea8fc6da686.png

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

id

username

password

lase_login

ip

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

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

883a8c3af1c476356de0d8040d8cbee3.png

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

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

2d349a542ed75a8b5bf779f2554625bb.png

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

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

b623d92bb9f6c2d9739d7352f8a324f6.png

第二个为“h”

bf3c9a8d26265f39e1e0633b05ae11fd.png

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

admin

zhangsan

lisi

wangwu

zhaoliu

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值