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表达式注入。
漏洞原理
触发条件
- 使用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表达式注入
- 再次进入
关键正则表达式
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("[");
参数绑定过程
- 将值传递给
tokenValue - 进行
PARAMETER_BINDING_PATTERN和EXPRESSION_BINDING_PATTERN匹配 - 取出占位符(如
?0) - 通过for循环将payload和占位符进行替换
- 执行
evaluateExpression
漏洞修复
修复方案
Spring Data MongoDB 3.3.4版本中增加了新的规则匹配表达式:
private static final Pattern SPEL_PARAMETER_BINDING_PATTERN = Pattern.compile("('\\?(\\d+d+))");
修复机制
- 对
binding(如:#{?0})进行匹配 - 将payload放入
innerSpelVariables的键值对中,key为特殊字符 - 使用三元运算符判断
expressionEvaluator是否为EvaluationContextExpressionEvaluator的实例 - 传入键值对中的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')");
防御建议
- 升级Spring Data MongoDB到3.3.4以上版本
- 避免在查询注解中直接使用SpEL表达式
- 对用户输入进行严格验证和过滤
- 使用参数化查询而非字符串拼接