
Образовательный анализ и эксплойт для доказательства концепции для CVE-2022-22965, уязвимости удаленного выполнения кода в Spring MVC/WebFlux через связывание данных на JDK 9+ с развертыванием Tomcat WAR.
Недавно в 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. (Приложения Spring MVC или Spring WebFlux, работающие на JDK 9+, могут быть уязвимы для удаленного выполнения кода (RCE) через привязку данных. Для конкретной эксплуатации требуется, чтобы приложение было развернуто как WAR на Tomcat. Если приложение развернуто как исполняемый jar Spring Boot (по умолчанию), оно не уязвимо для данной эксплуатации. Однако природа уязвимости более общая, и могут существовать другие способы ее эксплуатации.)". В данном анализе мы изучаем принцип уязвимости, воспроизводя этот CVE.
Прежде чем рассматривать принцип привязки параметров Spring MVC, давайте посмотрим на некоторые API, связанные с Java Bean.
Объявим следующий класс 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` и `того`, также есть атрибут `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
Кроме того, сравните различия в информации, полученной с помощью Introspector.getBeanInfo(Class.class) в разных версиях JDK: выше вывод для 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
C```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
По сравнению с JDK8, в JDK9 появилось два дополнительных атрибута: module и packageName. А в JDK11, помимо атрибутов module и packageName, есть еще два атрибута: nestHost и nestMembers.