1. SQL注入实战笔记:从入门到精通
作为一名长期从事Web安全测试的工程师,我经常遇到各种SQL注入漏洞。今天我想通过Sqli-labs这个经典的SQL注入练习平台,带大家全面了解SQL注入的各种攻击手法和防御策略。这篇文章将包含我多年实战中积累的经验和技巧,希望能帮助安全从业者更好地理解和防范这类漏洞。
2. 前置知识准备
2.1 Information Schema数据库详解
在MySQL中,information_schema是一个系统数据库,它包含了所有其他数据库的元数据信息。对于SQL注入攻击者来说,这个数据库就是获取目标数据库结构的"藏宝图"。
最常用的三张表是:
- SCHEMATA表:存储所有数据库名称
- TABLES表:存储所有表的信息
- COLUMNS表:存储所有列的信息
在实际注入中,我们通常会这样使用:
sql复制-- 获取当前数据库名
SELECT database();
-- 获取所有表名
SELECT table_name FROM information_schema.tables
WHERE table_schema=database();
-- 获取users表的所有列名
SELECT column_name FROM information_schema.columns
WHERE table_schema=database() AND table_name='users';
注意:不同数据库系统(如Oracle、SQL Server)的系统表结构有所不同,需要针对性调整查询语句。
2.2 URL编码与空格处理技巧
在构造注入payload时,正确处理特殊字符至关重要。特别是空格,它在URL中有多种表示方式:
- 标准URL编码:%20
- 表单编码简写:+
- 注释符后的空格:--后需要跟空格,但在URL中常用+代替
例如:
code复制?id=1' UNION SELECT 1,2,3 --+
这里的+号就表示--注释符后的空格。
3. 联合查询注入详解
3.1 基本注入流程
联合查询注入是最常见的一种SQL注入方式,适用于页面有数据回显的情况。完整的攻击流程如下:
- 判断闭合方式:尝试', ", '), "))等,观察是否报错
- 确定字段数量:使用ORDER BY递增测试
- 定位回显位置:使用UNION SELECT 1,2,3...
- 获取数据库信息:利用information_schema查询表结构
- 提取敏感数据:最终获取用户名密码等关键信息
3.2 实战案例:Less-1到Less-4
这四关展示了不同闭合方式的处理技巧:
| 关卡 | 闭合方式 | 示例Payload |
|---|---|---|
| Less-1 | 单引号 | 1' UNION SELECT 1,2,3 --+ |
| Less-2 | 无引号 | 1 UNION SELECT 1,2,3 --+ |
| Less-3 | 单引号加括号 | 1') UNION SELECT 1,2,3 --+ |
| Less-4 | 双引号加括号 | 1") UNION SELECT 1,2,3 --+ |
经验分享:在实际测试中,我通常会先用
'和"测试,如果都报错再尝试带括号的变体。快速判断闭合方式可以大大提高测试效率。
3.3 高级技巧:GROUP_CONCAT的使用
在获取表名或列名时,使用GROUP_CONCAT可以避免LIMIT限制:
sql复制?id=-1' UNION SELECT 1,2,GROUP_CONCAT(table_name)
FROM information_schema.tables
WHERE table_schema=database() --+
这个函数会将所有结果合并为一个字符串返回,非常实用。
4. 报错注入技术
4.1 报错注入原理
当页面不直接回显数据但会显示SQL错误信息时,可以使用报错注入。核心是利用数据库的报错机制来泄露信息。
最常用的两个函数是:
- updatexml()
- extractvalue()
它们的原理是故意构造错误的XML路径表达式,使数据库返回错误信息,同时将我们想获取的数据包含在错误信息中。
4.2 实战案例:Less-5和Less-6
基本payload格式:
sql复制?id=1' AND updatexml(1,concat(0x7e,database(),0x7e),1) --+
这里的0x7e是波浪号(~)的十六进制,用于在错误信息中标记出我们想要的数据。
避坑指南:有些WAF会检测updatexml等函数,可以尝试用floor(rand()*2)等替代方法。
5. 盲注技术详解
5.1 布尔盲注(Less-8)
当页面只有"是/否"两种状态时,使用布尔盲注。通过精心构造条件语句,根据页面反应来推断数据。
典型payload:
sql复制?id=1' AND ASCII(SUBSTR(database(),1,1))>115 --+
这个语句会检查数据库名的第一个字符的ASCII码是否大于115('s')。
5.2 时间盲注(Less-9和Less-10)
当页面没有任何可见变化时,可以使用时间盲注。通过SLEEP函数制造时间延迟来判断条件是否成立。
典型payload:
sql复制?id=1' AND IF(ASCII(SUBSTR(database(),1,1))>115,SLEEP(2),1) --+
如果第一个字符的ASCII码大于115,页面响应会延迟2秒。
实战技巧:时间盲注速度很慢,建议先使用布尔盲注缩小范围,再用时间盲注精确确认。
6. POST注入与HTTP头注入
6.1 POST注入(Less-11到Less-17)
POST注入与GET注入原理相同,只是注入点从URL参数变成了POST表单数据。需要注意以下几点:
- 使用Burp Suite等工具拦截修改POST请求
- 注意Content-Type可能是application/x-www-form-urlencoded或multipart/form-data
- 登录框注入可能需要先绕过认证
6.2 HTTP头注入(Less-18到Less-20)
很多开发者会忽略对HTTP头的过滤,导致以下头字段可能成为注入点:
- User-Agent
- Referer
- Cookie
- X-Forwarded-For
典型payload:
sql复制User-Agent: ' AND updatexml(1,concat(0x7e,database(),0x7e),1) AND '1'='1
7. 高级绕过技术
7.1 注释符过滤绕过(Less-23)
当注释符(--, #)被过滤时,可以使用布尔逻辑来闭合语句:
sql复制?id=1' UNION SELECT 1,database(),3 AND '1'='1
7.2 二次注入(Less-24)
二次注入的特别之处在于恶意输入先被存储,之后才被使用。典型攻击步骤:
- 注册用户名:admin'#
- 使用该账号修改密码
- 实际执行的SQL会变成修改admin的密码
7.3 关键字过滤绕过(Less-25和Less-26)
当or/and等关键字被过滤时,可以尝试以下方法:
- 双写关键字:oorr, anandd
- 使用符号替代:||替代OR, &&替代AND
- 使用注释分割:o/**/r
对于空格过滤,可以使用以下替代:
- /**/
-
- 括号包裹
8. 防御建议
根据OWASP Top 10的建议,防范SQL注入的最佳实践包括:
- 使用预编译语句(Prepared Statements):这是最有效的防御手段
- 输入验证:白名单验证所有输入数据
- 最小权限原则:数据库账户只赋予必要权限
- Web应用防火墙(WAF):作为纵深防御的一环
- 定期安全测试:包括代码审计和渗透测试
9. 个人实战经验分享
在多年的渗透测试工作中,我总结了以下几点经验:
- 不要依赖自动化工具:手工测试往往能发现更多漏洞
- 注意异常处理页面:有时错误信息会泄露有价值的信息
- 测试所有输入点:包括隐藏字段、HTTP头等
- 保持学习:新的数据库版本和WAF规则不断出现,需要持续更新知识
最后提醒:本文所有技术仅限合法授权测试使用,未经授权的测试可能触犯法律。安全从业者应当遵守职业道德,共同维护网络安全。