블로그 이전
https://skitttles.me/posts/spring4shell_poc_cve-2022-22965/
여러 글을 정리하여 옮겼습니다 😀
중국의 한 보안 전문가가 올린 Spring Core 프레임워크 취약점 POC 화면이 발단이 되어 여러 POC가 웹 상에 올라왔습니다. 해당 취약점은 "Spring4Shell" 또는 "SpringShell"로 불리며 2022년 03월 31일 Spring 개발자에 의해 'CVE-2022-22965' 취약점으로 추가되었습니다.
Spring4Shell 취약점은 Spring Core 프레임워크에서 특정 조건 하에 Remote Code Execution이 가능한 취약점이며 Spring 프레임워크가 매개변수를 바인딩하는 과정에서 'class' 객체가 노출되어 발생합니다.
공격자는 해당 'class' 객체의 자식 객체인 'class.module.classLoader'에 웹 매개변수를 통해 접근할 수 있으며 로깅 관련 클래스(AccessLogValve)를 이용하여 웹 쉘 코드를 업로드한 후, 명령어를 실행할 수 있습니다.
취약 조건
- Java 9 이상
- Apache Tomcat 서버
- Spring Framework 버전 5.3.0 ~ 5.3.17, 5.2.0 ~ 5.2.19 및 이전 버전
- spring-webmvc 또는 spring-webflux 종속성
- WAR 형태로 패키징
사실, 비교되는 'Log4Shell'에 비해 취약 조건이 까다롭지만 취약점 공격 방법이 매우 쉬우므로 여건이 된다면 패치를 하는 것이 좋을 것으로 판단됩니다.
Spring4Shell 취약점은 매개변수를 바인딩 할 때 발생합니다. 그러면 Spring에서의 매개변수 바인딩과 접근이 어떤 형태로 이뤄지며 어떤 과정에서 취약점이 도출되는지 알아보겠습니다.
Spring Core에서는 @RequestMapping Annotation을 이용해 매개변수를 바인딩 및 접근하는 2가지 방법이 존재합니다.
아래 캡처와 같이 Map에서 매개변수에 접근할 수 있으며 매개변수의 값은 'model.data'라는 Model Object에 저장되어 사용됩니다.
POJO(Plain Old Java Object)라고 불리는 일반 자바 객체의 속성에 URL을 통해 입력된 매개변수가 매핑되어 사용될 수 있습니다.
아래 캡처에서 매개변수는 'Greeting.greeting' 객체의 속성에 바인딩되며, 실제 요청이 오면 'Greeting' 타입의 인스턴스에 접근하여 속성을 사용할 수 있습니다.
아래와 같이 getter, setter를 이용해 매개변수에 접근할 수 있습니다.
해당 취약점은 특정 상황에서 'class' 라는 특수한 변수가 사용자에게 노출되어 'classLoader' 에 접근할 수 있을때 발생하며 상세한 절차는 다음과 같습니다.
패치 전에는 'class'의 자식 객체에 대한 직접 접근을 필터링하기 위해 'CachedIntrospectionResults.java' 에서 아래와 같이 'class.classLoader' 및 'class.protectionDomain' 을 필터링을 하였었지만 'class.module.classLoader' 을 사용하여 우회 가능하였습니다.
if (Class.class == beanClass &&
("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) {
continue;
}
Spring 개발자에 의해 패치가 되어 'CachedIntrospectionResults.java' 가 아래와 같이 수정되었습니다.
docker run -d -p 8082:8080 --name springrce -it vulfocus/spring-core-rce-2022-03-29
POC 실행 시 취약한 서버에 웹쉘이 생성됩니다.
POC 요청 패킷의 매개변수에 'class'의 로깅 관련 객체가 사용되는 것을 확인할 수 있습니다.
'class.module.classLoader.resources.context.parent.pipeline.first.pattern' 매개변수에 웹쉘의 코드를 담고 있습니다.
아래 URL에 접속 시 id 명령어가 실행되어 결과가 출력됩니다.
http://192.168.56.105:8082/tomcatwar.jsp?pwd=j&cmd=id
KISA 권고 사항 인용
- JDK 9 이상의 Spring 프레임워크 사용하는 경우
- Spring Framework 5.3.0 ~ 5.3.17, 5.2.0 ~ 5.2.19 및 이전 버전
※ JDK 8 이하의 경우 취약점의 영향을 받지 않음
JDK 버전 확인: 아래 명령 입력
java -version
프로젝트가 jar, war 패키지로 돼 있는 경우 zip 확장자로 변경하여 압축풀기
이후 아래와 같이 'spring-beans-.jar', 'spring.jar', 'CachedIntrospectionResuLts.class' 로 검색
find . -name spring-beans*.jar
KISA 권고 사항 인용
import org.springwork.core.Ordered;
import org.springwork.core.annotation.Order;
import org.springwork.web.bind.WebDataBinder;
import org.springwork.web.bind.annotation.ControllerAdvice;
import org.springwork.web.bind.annotation.InitBinder;
@ControllerAdvice
@Order(10000)
public class BinderControllerAdvice {
@InitBinder
public setAllowedFields(WebDataBinder dataBinder) {
String[] denylist = new String[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};
dataBinder.setDisallowedFields(denylist);
}
}
[1] https://www.extrahop.com/company/blog/2022/a-technical-analysis-of-how-spring4shell-works/
[2] https://unit42.paloaltonetworks.com/cve-2022-22965-springshell/
[3] https://github.com/spring-projects/spring-framework/commit/002546b3e4b8d791ea6acccb81eb3168f51abb15
[4] https://github.com/lunasec-io/lunasec/blob/master/docs/blog/2022-03-30-spring-core-rce.mdx#who-is-impacted
[6] https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=66592
[7] https://github.com/TheGejr/SpringShell
[8] https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/