Spring FW) 제로데이 취약점 CVE-2022-22965

작성: 2022.04.05

수정: 2022.04.05

읽는시간: 00 분

IT ⁄ Computer/News

반응형

SpringShell

CVE-2022-22965

JDK9+ 버전을 사용해 Spring MVC 혹은 Spring WebFlux 어플리케이션을 구동하고 있다면 데이터 바인딩을 통한 원격 코드 실행(Remote Code Execution) 취약점에 노출 될 수 있다는 소식이 2022년 3월 31일 일요일에 공개되었습니다.

스프링 프레임워크가 워낙에 광범위하게 사용되고 있으며, 해당 취약점의 심각도가 높다 보니 CVSS 스코어가 9.8점으로 꽤나 높게 나왔습니다.

지금은 보통 SpringShell 혹은 Spring4Shell 라고 불리고 있는 해당 취약점에 대해 알아보겠습니다.

영향을 받는 환경

  • JDK 9+

  • Apache Tomcat을 서블릿 컨테이너로 사용

  • 전통적인 WAR 패키징 (스프링 부트의 jar 패키징은 해당 안됨)

  • Spring Web MVC 혹은 Spring Webflux 사용

  • Spring Framework 버전이 5.3.0<=<=5.3.17, 5.2.0<=<=5.2.19, 혹은 그 이하

근본 원인

스프링 프레임워크의 getCachedIntrospectionResults 메서드가 파라미터를 바인딩 할 때 바람직하지 않게 클래스 객체를 외부에 노출하며 취약점이 생기게 되었습니다.

기본적인 스프링 데이터 바인딩 메커니즘은 개발자들이 HTTP 리퀘스트의 세부 정보를 어플리케이션의 특정 객체들에 바인딩 할 수 있도록 해 주는데요, 예를 들어 아래의 코드가 있을 때

Trade.java

public class Trade{
  private String buy;
  private String sell;
  public String getBuy() {
      return buy;
  }
  public void setSell(String sell) {
      this.sell = sell;
  }
}

Controller

@Controller
public class TradeController{
    @ReuqestMapping("trades")
    public String handleTradeRequest(Trade trade, Model map) {
        String msg = String.format("trade request. buy:%s, sell:%s", trade.getBuy(), trade.getSell());
        map.addAttribute("msg", msg);
        return "trade-result";
    }
}

이러한 상황에서 개발자들은 보통 해당 컨트롤러를 위해 request builder를 생성함으로서 웹 사용자들이 Trade 객체에 원격적으로 접근 할 수 있게끔 해줍니다.

/trades?buy=buyValue&sell=sellValue

웹 사용자가 위의 요청으로 Trade 객체 속성에 접근할 때, 스프링프레임워크의 바인딩 절차에 따라 getCachedIntrospectionResults 메서드를 호출하여 캐시에 개체의 property를 저장하게 됩니다.

그런데, getCachedIntrospectionResults 메서드의 반환 객체에는 해당 클래스 객체가 포함되어 있어 웹 사용자가 아래와 같은 요청만 보내면 간단히 해당 클래스 객체를 얻을 수 있게 됩니다.

/trades?class

웹 사용자에게 클래스 객체를 노출하는건 매우 위험하며, 이 경우 다양한 방법에 의해 원격 코드 실행(Remote Code Execution) 위협에 노출 되게 됩니다.

대처 방법

다행히도 스프링 팀에서 발빠르게 새로운 버전을 발표 해 주었습니다.

  • Spring Framework 버전 5.2.20 혹은 5.3.18 이상으로 마이그레이션

  • Spring Boot 버전 2.5.12 혹은 2.6.6 이상으로 마이그레이션

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);
    }
}

JDK 9 이상에 서블릿 컨테이너로는 톰캣 사용에 war 패키징 등등 취약점에 해당하는 조건이 제법 여러가지 있다보니 war패키징 대신 jar패키징을 하고 있다거나 톰캣을 사용하지 않는다는 이유 등으로 아무런 대처 없이 지나 갈 수도 있겠습니다.

하지만 Log4j 취약점 사태에서의 경험했던 것 처럼, 또 다른 어떠한 우회 경로가 나타날지 모르기때문에 미리 최신의 스프링 부트 버전으로 변경 해 주는 것이 좋을거라 생각합니다. 이상입니다.

Ref

반응형