最近、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 を再現することで脆弱性の原理を学びます。
springmvc のパラメータバインディングの原理を見る前に、まず 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());
// }
}
出力:```text Property: age,Class:int Property: class,Class:class java.lang.Class Property: name,Class:class java.lang.String
想定どおりのageとname以外にも、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
The INPUT section is empty — no source text was provided to translate. Please supply the Markdown content for chunk 11.```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の2つの属性が追加され、JDK11ではmoduleとpackageNameの属性に加えてnestHostとnestMembersのさらに2つの属性があります。