CVE-2022-22980 Spring Data MongoDB SpEL表达式注入
字数 1365 2025-08-27 12:33:43

Spring Data MongoDB SpEL表达式注入漏洞(CVE-2022-22980)分析

漏洞概述

CVE-2022-22980是Spring Data MongoDB中的一个SpEL表达式注入漏洞,影响版本为3.3.4及以下。当使用@Query@Aggregation注解进行数据库查询,并且使用了占位符获取参数时,可能导致SpEL表达式注入。

漏洞原理

触发条件

  1. 使用Spring Data MongoDB 3.3.4或更低版本
  2. 在Repository中使用@Query@Aggregation注解
  3. 查询语句中使用占位符参数(如:#{?0})

漏洞位置

漏洞主要发生在org.springframework.data.mongodb.util.json.ParameterBindingJsonReader#bindableValueFor方法中,当绑定参数时会触发SpEL表达式解析。

详细分析

关键代码路径

  1. StringBasedMongoQuery#createQuery - 创建查询的入口
  2. ParameterBindingJsonReader#bindableValueFor - 参数绑定核心方法
  3. ParameterBindingDocumentCodec - 参数绑定编解码器

漏洞触发流程

  1. 第一次参数绑定:

    • 进入bindableValueFor方法
    • expressionEvaluatorParameterBindingDocumentCodec
    • 仅返回空对象,不触发漏洞
  2. 第二次参数绑定:

    • 再次进入bindableValueFor方法
    • expressionEvaluator变为DefaultSpELExpressionEvaluator
    • 执行getValue触发SpEL表达式注入

关键正则表达式

private static final Pattern PARAMETER_ONLY_BINDING_PATTERN = Pattern.compile("^\\(\\d+)$");
private static final Pattern PARAMETER_BINDING_PATTERN = Pattern.compile("\\?(\\d+");
private static final Pattern EXPRESSION_BINDING_PATTERN = Pattern.compile("[");

参数绑定过程

  1. 将值传递给tokenValue
  2. 进行PARAMETER_BINDING_PATTERNEXPRESSION_BINDING_PATTERN匹配
  3. 取出占位符(如?0)
  4. 通过for循环将payload和占位符进行替换
  5. 执行evaluateExpression

漏洞修复

修复方案

Spring Data MongoDB 3.3.4版本中增加了新的规则匹配表达式:

private static final Pattern SPEL_PARAMETER_BINDING_PATTERN = Pattern.compile("('\\?(\\d+d+))");

修复机制

  1. binding(如:#{?0})进行匹配
  2. 将payload放入innerSpelVariables的键值对中,key为特殊字符
  3. 使用三元运算符判断expressionEvaluator是否为EvaluationContextExpressionEvaluator的实例
  4. 传入键值对中的key(如#__QVar0)而非原始payload,阻止SpEL表达式注入

漏洞利用示例

漏洞代码示例

@Repository
public interface UserRepository extends MongoRepository<User, String> {
    @Query(value = "{'id': :#{?0}}")
    User findByIdSpEL(String id);
}

攻击向量

攻击者可以构造恶意的SpEL表达式作为参数传入:

userRepository.findByIdSpEL("T(java.lang.Runtime).getRuntime().exec('calc')");

防御建议

  1. 升级Spring Data MongoDB到3.3.4以上版本
  2. 避免在查询注解中直接使用SpEL表达式
  3. 对用户输入进行严格验证和过滤
  4. 使用参数化查询而非字符串拼接

参考链接

  1. threedr3am/learnjavabug示例代码
  2. Spring官方修复提交
Spring Data MongoDB SpEL表达式注入漏洞(CVE-2022-22980)分析 漏洞概述 CVE-2022-22980是Spring Data MongoDB中的一个SpEL表达式注入漏洞,影响版本为3.3.4及以下。当使用 @Query 或 @Aggregation 注解进行数据库查询,并且使用了占位符获取参数时,可能导致SpEL表达式注入。 漏洞原理 触发条件 使用Spring Data MongoDB 3.3.4或更低版本 在Repository中使用 @Query 或 @Aggregation 注解 查询语句中使用占位符参数(如 :#{?0} ) 漏洞位置 漏洞主要发生在 org.springframework.data.mongodb.util.json.ParameterBindingJsonReader#bindableValueFor 方法中,当绑定参数时会触发SpEL表达式解析。 详细分析 关键代码路径 StringBasedMongoQuery#createQuery - 创建查询的入口 ParameterBindingJsonReader#bindableValueFor - 参数绑定核心方法 ParameterBindingDocumentCodec - 参数绑定编解码器 漏洞触发流程 第一次参数绑定: 进入 bindableValueFor 方法 expressionEvaluator 为 ParameterBindingDocumentCodec 仅返回空对象,不触发漏洞 第二次参数绑定: 再次进入 bindableValueFor 方法 expressionEvaluator 变为 DefaultSpELExpressionEvaluator 执行 getValue 触发SpEL表达式注入 关键正则表达式 参数绑定过程 将值传递给 tokenValue 进行 PARAMETER_BINDING_PATTERN 和 EXPRESSION_BINDING_PATTERN 匹配 取出占位符(如 ?0 ) 通过for循环将payload和占位符进行替换 执行 evaluateExpression 漏洞修复 修复方案 Spring Data MongoDB 3.3.4版本中增加了新的规则匹配表达式: 修复机制 对 binding (如 :#{?0} )进行匹配 将payload放入 innerSpelVariables 的键值对中,key为特殊字符 使用三元运算符判断 expressionEvaluator 是否为 EvaluationContextExpressionEvaluator 的实例 传入键值对中的key(如 #__QVar0 )而非原始payload,阻止SpEL表达式注入 漏洞利用示例 漏洞代码示例 攻击向量 攻击者可以构造恶意的SpEL表达式作为参数传入: 防御建议 升级Spring Data MongoDB到3.3.4以上版本 避免在查询注解中直接使用SpEL表达式 对用户输入进行严格验证和过滤 使用参数化查询而非字符串拼接 参考链接 threedr3am/learnjavabug示例代码 Spring官方修复提交