
CVE-2022-22965에 대한 교육용 분석 및 개념 증명 익스플로잇, JDK 9+ 및 Tomcat WAR 배포 환경에서 데이터 바인딩을 통한 Spring MVC/WebFlux 원격 코드 실행 취약점.
최근 Spring에서 대규모 CVE 취약점이 발견되었습니다. CVE 정보에 따르면 "A Spring MVC or Spring WebFlux application running on JDK 9+ may be vulnerable to remote code execution (RCE) via data binding. The specific exploit requires the application to run on Tomcat as a WAR deployment. If the application is deployed as a Spring Boot executable jar, i.e. the default, it is not vulnerable to the exploit. However, the nature of the vulnerability is more general, and there may be other ways to exploit it.(JDK 9+에서 실행되는 Spring MVC 또는 Spring WebFlux 애플리케이션은 데이터 바인딩을 통한 원격 코드 실행(RCE)에 취약할 수 있습니다. 구체적인 악용을 위해서는 애플리케이션이 WAR 배포로 Tomcat에서 실행되어야 합니다. 애플리케이션이 Spring Boot 실행 가능 jar(기본값)로 배포된 경우 악용에 취약하지 않습니다. 그러나 취약점의 성격은 더 일반적이며 이를 악용할 수 있는 다른 방법이 있을 수 있습니다.)" 본 분석은 해당 CVE를 재현하여 취약점 원리를 학습합니다.
Spring MVC의 매개변수 바인딩 원리를 살펴보기 전에 Java Bean 관련 API를 먼저 살펴보겠습니다.
다음과 같은 Java Bean 클래스를 선언합니다:```java public class User { private String name;
public User() {
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public int getAge() {
return 18;
}
}
다음 테스트 코드를 통해 Introspector.getBeanInfo가 가져오는 정보를 확인해보겠습니다.```java
@Test
public void testIntrospector() throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
for (PropertyDescriptor pdesc:beanInfo.getPropertyDescriptors()){
System.out.println("Property: " + pdesc.getName() + ",Class:" + pdesc.getPropertyType());
}
// for (MethodDescriptor md:beanInfo.getMethodDescriptors()) {
// System.out.println("Method: " + md.getName());
// }
}
(no content provided)```text Property: age,Class:int Property: class,Class:class java.lang.Class Property: name,Class:class java.lang.String
예상한 age와 그 외에도 class 속성이 하나 더 있습니다. 클래스 이름은 Class입니다. 만약 계속해서 Introspector.getBeanInfo(Class.class)를 호출하면 classLoader 등 더 많은 정보를 얻을 수 있습니다:```text jdk11:
Property: annotatedInterfaces
Property: annotatedSuperclass
Property: annotation
Property: annotations
Property: anonymousClass
Property: array
Property: canonicalName
Property: class
Property: classLoader
Property: classes
Property: componentType
Property: constructors
Property: declaredAnnotations
Property: declaredClasses
Property: declaredConstructors
Property: declaredFields
Property: declaredMethods
Property: declaringClass
Property: enclosingClass
Property: enclosingConstructor
Property: enclosingMethod
Property: enum
Property: enumConstants
Property: fields
Property: genericInterfaces
Property: genericSuperclass
Property: interface
Property: interfaces
Property: localClass
Property: memberClass
Property: methods
Property: modifiers
Property: module
Property: name
Property: nestHost
Property: nestMembers
Property: package
Property: packageName
Property: primitive
Property: protectionDomain
Property: signers
Property: simpleName
Property: superclass
Property: synthetic
Property: typeName
Property: typeParameters
또한 다른 JDK 버전에서 Introspector.getBeanInfo(Class.class)로 얻은 정보의 차이를 비교해 보면, 위쪽은 jdk-11에서의 출력이고, 아래쪽은 JDK8에서의 출력입니다:```text jdk8: Property: annotatedInterfaces Property: annotatedSuperclass Property: annotation Property: annotations Property: anonymousClass Property: array Property: canonicalName Property: class Property: classLoader Property: classes Property: componentType Property: constructors Property: declaredAnnotations Property: declaredClasses Property: declaredConstructors Property: declaredFields Property: declaredMethods Property: declaringClass Property: enclosingClass Property: enclosingConstructor Property: enclosingMethod Property: enum Property: enumConstants Property: fields Property: genericInterfaces Property: genericSuperclass Property: interface Property: interfaces Property: localClass Property: memberClass Property: methods Property: modifiers Property: name Property: package Property: primitive Property: protectionDomain Property: signers Property: simpleName Property: superclass Property: synthetic Property: typeName Property: typeParameters
````text
Property: annotatedInterfaces
Property: annotatedSuperclass
Property: annotation
Property: annotations
Property: anonymousClass
Property: array
Property: canonicalName
Property: class
Property: classLoader
Property: classes
Property: componentType
Property: constructors
Property: declaredAnnotations
Property: declaredClasses
Property: declaredConstructors
Property: declaredFields
Property: declaredMethods
Property: declaringClass
Property: enclosingClass
Property: enclosingConstructor
Property: enclosingMethod
Property: enum
Property: enumConstants
Property: fields
Property: genericInterfaces
Property: genericSuperclass
Property: interface
Property: interfaces
Property: localClass
Property: memberClass
Property: methods
Property: modifiers
Property: module
Property: name
Property: package
Property: packageName
Property: primitive
Property: protectionDomain
Property: signers
Property: simpleName
Property: superclass
Property: synthetic
Property: typeName
Property: typeParameters
jdk9는 JDK8에 비해 module과 packageName 두 가지 속성이 더 있으며, JDK11에서는 module과 packageName 속성 외에도 nestHost와 nestMembers라는 두 가지 속성이 더 있습니다.