1. Spring4Shell 개요
- Spring Core 프레임워크에서 특정 조건 하에 RCE(Remote Code Execution)가 가능한 취약점
- Spring 프레임워크가 매개변수를 바인딩하는 과정에서 ‘class’ 객체가 노출되어 발생
- 공격자는 해당 ‘class’ 객체에서 로깅 관련 기능을 사용해 웹 쉘 코드를 업로드하여 명령어를 실행 가능
2. 취약점 POC
(1) 테스트 환경
- JDK 11
- tocat-9.0.59
- Spring Framework 5.3.15
(2) 매개변수 바인딩과 사용자 접근
Spring에서는 POJO(Plain Old Java Object)라고 불리는 일반 자바 객체의 속성에 URL을 통해 입력된 매개변수를 매핑하여 사용할 수 있습니다.
// 객체클래스
public class Greeting {
private long id;
private String content;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
//컨트롤러
@Controller
public class HelloController {
@GetMapping("/greeting")
public String greetingForm(Model model) {
model.addAttribute("greeting", new Greeting());
return "hello";
}
@PostMapping("/greeting")
public String greetingSubmit(@ModelAttribute Greeting greeting, Model model) {
return "hello";
}
}
위와 같이 Greetring이라는 객체와 Controller를 생성하면 가정한다면 일반적인 사용자는 “http:///greeting?id=test&content=test”과 같은 URL로 접근할 수 있습니다.
(3) 취약점 공격
해당 취약점은 특정 상황에서 ‘class’라는 특수한 변수가 사용자에게 노출될 때 발생합니다. 현재 공개된 방식은 ‘classLoader’를 사용하여 Tomcat 로그를 이용하여 JSP 웹 쉘을 생성하는 방식입니다.
1) 취약한 도커 이미지 실행
docker build . -t spring4shell && docker run -p 8080:8080 spring4shell
2) POC 코드 실행
python exploit.py --url "http://localhost:8080/helloworld/greeting"
2-1) POC 코드 실행 시 Body에 class의 로깅 관련 객체가 사용되는 것을 확인할 수 있습니다. ‘class.module.classLoader.resources.context.parent.pipeline.first.pattern’ 매개 변수에 웹 쉘 코드를 담아 보내는 것을 확인할 수 있습니다.
2-2) POC 코드가 정상적으로 실행이 됐을 경우 웹 쉘 파일이 서버에 생성되는 것을 확인할 수 있습니다.
$ find -name shell.jsp
./usr/local/tomcat/webapps/ROOT/shell.jsp
3) 웹쉘 접속 * 명령어 실행
생성한 웹 쉘에 원하는 명령어를 파라마터에 대입하여 요청할 경우 실행되는 것을 확인할 수 있습니다.
3. 영향받는 버전
CVE-2022-22965(Spring4Shell) ■ JDK 9 이상의 Spring 프레임워크 사용하는 경우
- Spring Framework 5.3.0 ~ 5.3.17
- Spring Framework 5.2.0 ~ 5.2.19
- 및 이전 버전 ※ JDK 8 이하의 경우 취약점의 영향을 받지 않음
4. 취약한 버전 확인 방법
(1) Java 버전 확인
: java -version
(2) Spring 버전 확인
1) pom.xml 내 확인
2) getVersion() 메서드를 사용 확인
public class CheckSpringVersion{
@Test
public void versionTest() throws Exception{
String test=org.springframework.core.SpringVersion.getVersion();
System.out.println(test);
}
}
5. 대응방안
- 제조사 홈페이지를 통해 최신버전으로 업데이트 적용
- 제조사 홈페이지에 신규버전이 계속 업데이트되고 있어 확인 후 업데이트 적용 필요
- CVE-2022-22965(Spring4Shell)
- Spring Framework 5.3.18, 5.2.20 버전으로 업데이트
- 신규 업데이트가 불가능할 경우 아래와 같이 조치 적용
- CVE-2022-22965(Spring4Shell) ※ 프로젝트 패키지 아래 해당 전역 클래스 생성 후 재 컴파일(테스트 필요)
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);
}
}
※ 참고 ※
https://uxicode.tistory.com/entry/%EB%B0%94%EC%9D%B8%EB%94%A9%EC%9D%B4%EB%9E%80
https://velog.io/@thelm3716/spring4shell-%EB%B6%84%EC%84%9D-%EA%B8%80-%EC%A0%95%EB%A6%AC-CVE-2022-22965
https://www.fastly.com/blog/spring-has-sprung-breaking-down-cve-2022-22963-and-spring4shell-cve-2022
https://unit42.paloaltonetworks.com/cve-2022-22965-springshell/
https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=66592
https://javamana.com/2022/04/202204022300005716.html
https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/
https://hackyboiz.github.io/2022/04/03/l0ch/2022-04-03/
https://snyk.io/blog/spring4shell-zero-day-rce-spring-framework-explained/
https://github.com/reznok/Spring4Shell-POC