Spring4Shell – A Deep Understanding (CVE-2022–22965)

(this blog-post was initially published by our colleague Mouad Kondah on Medium)

On March 29, 2022, a critical Remote Code Execution vulnerability CVE-2022-22965 was disclosed by a Chinese Researcher targeting the Spring Java framework, a very popular open-source framework for Java Applications.

In this blog-post we provide a detailed explanation of CVE-2022-22965, providing the necessary background and a deep comprehensive understanding of the vulnerability. 

The vulnerability dubbed “Spring4Shell” affects Spring Core and allows an attacker to send a series of specially crafted HTTP requests to bypass a patch that has been put in place for  CVE-2010–1622, leading to remote code execution on the target system running the vulnerable code. 

There are a number of publicly available Proof of Concept (PoC) exploits, The Kudelski Security Cyber Fusion Center recommends that organizations should identify impacted applications and apply the available patches or mitigations immediately (see Workarounds and Mitigations). 

We are closely investigating and monitoring additional information about this vulnerability and will update this advisory as more information becomes available.

Affected Applications Versions

In order to exploit the vulnerabilities the following requirements must be met: 

Technical Details

In this section, we offer a detailed explanation of CVE-2022-22965, providing the necessary background and a comprehensive understanding of the vulnerability.

  • What is CVE-2022–22965 ( how is it linked to CVE-2010–1622)? 
  • Why does it only affects JDK9+? 
  • Why does it only affects Spring MVC default binding? 
  • Why does it only affects Spring applications deployed on Tomcat using WAR packaging?
  • How does the suggested temporary workaround works? 
  • How did Spring team fixed CVE-2022–22965

If you are not familiar with Tomcat jsp files, going quickly through this article is a good start. 

If you’re not too technical, you can skip straight to Exploiting Tomcat ClassLoader section.

Many PoCs are available, for example this one: https://github.com/TheGejr/SpringShell. To set up a suitable environment for applying the PoC you can have a look here or here for details.

Spring Binding Background

Data binding is allows user input to be dynamically bound to data objects specified (POJO/JavaBean).

Spring provides the so-called DataBinder to do exactly that.

The JavaBean class

A JavaBean is simply a class with a default no-argument constructor, which follows a naming convention where (by way of example) a property named vulnerability  would have a setter method setVulnerability(..) and a getter method getVulnerability().

The PropertyEditor class

Java has an interface called PropertyEditor under the java.beans package. It allow users to edit a property value of a given type.

Spring heavily uses the concept of PropertyEditors for managing conversion between an Object and a String. For example, a Vulnerability object can be represented in a human readable way while it’s still possible to convert the human readable form back to the original Object. This behavior can be achieved by registering custom editors, of type java.beans.PropertyEditor such as VulnerabilityEditor.

The PropertyDescriptor class

A PropertyDescriptor describes one property that a Java Bean exports via a pair of accessor methods.

In essence, many object properties can be changed by combining PropertyDescriptors and PropertyEditors. Spring uses the java.beans.PropertyEditorManager to find the property editors needed. An example is shown below.

The CachedIntrospectionResults class

CachedIntrospectionResults is an internal class that caches JavaBeans PropertyDescriptor information for a Java class.

Bean Manipulation and BeanWrapper

The BeanWrapper interface and its corresponding implementation (BeanWrapperImpl) are quite important classes in the Java Beans package.

Part of how BeanWrapper works is implied by its name: it wraps a bean to perform actions on that bean, such as setting and retrieving properties. As quoted in the javadoc.

The BeanWrapper offers functionality to set and get property values, get property descriptors, and query properties to determine if they are readable or writable. Also, the BeanWrapper offers support for nested properties, enabling the setting of properties on sub-properties to an unlimited depth. The BeanWrapper usually is not used by application code directly but is used by the DataBinder and the BeanFactory.

[….]

Setting and getting properties is done by using the setPropertyValue, setPropertyValues, getPropertyValue, and getPropertyValues methods which come with a couple of overloaded variants.

https://docs.spring.io/spring-framework/docs/3.0.0.M3/spring-framework-reference/html/ch06s04.html

JavaBeans specify conventions to indicate objects’ properties. The following table lists examples of these conventions.

The following code snippets show some examples of how to retrieve and manipulate some of the properties of instantiated classes.

Spring MVC Data binding

Spring makes use of ServletRequestDataBinder to bind its values. ServletRequestDataBinder is a special DataBinder to perform data binding from servlet request parameters to JavaBeans. An example of usage is shown below. Under the hood BeanWrapperImp  is used and responsible for set up the values.

Basically, when a request comes in the servlet, it gets dispatched until it reaches ServletModelAttributeMethodProcessor, a Servlet-specific ModelAttributeMethodProcessor that applies data binding through a WebDataBinder of type ServletRequestDataBinder. ServletRequestDataBinder tries to bind the values as show below.

It delegates to DataBinder.doBind(..)

Next, Databinder#applyPropertyValues is invoked with properties to apply.

As shown above, we get a propertyAccessor (beanWrapperImpl wrapping our target object) and invoke setPropertyValues which delegates to AbstractNestablePropertyAccessor#setPropertyValue for each value.

The logic where the setter is invoked is shown below.

Basically, when AbstractNestablePropertyAccessor#setPropertyValue is invoked, its says like look, we have this property class.module.classLoader …..  and we want it to be set it the target instance with the surfaced value. However, as seen, properties are nested, getPropertyAccessorForPropertyPath is invoked to obtain a propertyAccessor for the target nested field. The getPropertyAccessorForPropertyPath will recursively navigate to return a property accessor for the nested property path.

At some point the call reach BeanWrapperImp#getLocalPropertyHandler to obtain a BeanPropertyHandler used to take out a nested property value using the wrapped property descriptor and continues the recursion until it reaches our target property accessor.

As shown above, BeanWrapperImp caches property descriptors  and critical property descriptors like the one for class.classLoader…  could be resolved. 

Yes if critical objects are exposed and can be set, bad stuff can happen . 

Spring made sure that that property descriptor likeclass.classloader and class.protectionDomain  were ignored for CVE-2010–1622

However, with the introduction of module class in JDK9, this check is no longer valid and the property descriptor for class.module.classloader…   can be set with the value we provide if a setter is available.

In fact, the bypass comes from the fact that Class.class == beanClass condition is no longer satisfied using java.lang.Module, classLoader can be obtained using Module#getClassLoader.  

As shown in the following figure, we bypassed the check.

The figure below shows that the property descriptor for the classLoader was populated in the cache.

Let’s see what we’ve learned so far: We’re able to modify not only specific object attributes but also class.module.classLoader nested properties if a setter is there. What can we do with that ? This leads us to next section.

Exploiting Tomcat ClassLoader

Since JDK9, a new module object has been introduced.

A small inspection shows that classloader can be obtained through this Module object.

This means we can manipulate some class loader properties using class.module.classloader.{something}… and bypass Spring filtering (see below).

In fact, to refuse access to classLoader and protectionDomain child properties, Spring checks for “class.classLoader” and “class.protectionDomain” ( see condition below: Class.class == beanClass), but the logic can be bypassed with the following property name “class.module.classLoader”. 

We can target class.module.classLoader.resources.context.parent.pipeline.first.* which corresponds to  AccessLogValve, a class that outputs the access log to a file.

We can modify its attributes such as  class.module.classLoader.resources.context.parent.pipeline.first.pattern and other properties and cause a JSP file to be created in the webapps/ROOT directory.

As shown below write methods are available

To set the Tomcat logging properties, requests can be issued as follows (some stuff is properly encoded to avoid bad requests).

Tomcat server’s logging properties are thus altered via the ParallelWebappClassLoader

A file will be written to: webapps/ROOT/happyshell.jsp and it will contain the payload from the Tomcat pattern property shown below, that is, the webshell code (surfaced on the pattern property above).

An arbitrary command can be passed using the query parameter cmd, it gets executed and response will be written back the to the client. For example we can issue the request below. 

curl http://localhost:8080/happyshell.jsp?cmd=whoami

and it would return

root 

Spring has released new versions of the Spring framework that are no longer vulnerable to this critical severity vulnerability. 

Organizations maintaining Java applications that leverage the vulnerable versions of the Spring Framework should update to Spring 5.3.18 and 5.2.20. 

Official bugs were fixed on March 31 in versions 5.3.18 and 5.2.20. The main patch is the following.

The new patch has more strict type restrictions than the CVE-2010–1622 vulnerability patch, allowing only name variants of class properties. A second check has been added to ignore propertyDescriptors of type ClassLoader and ProtectionDomain. 

Solution

Today, Spring Framework versions 5.3.18 and 5.2.20 which address the vulnerability have already been released. Spring Boot versions 2.6.6 and 2.5.12 that depends on Spring Framework 5.3.18 have also been released, and CVE-2022-22965 has been published. Follow the official Spring statement for further updates: https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement#status 

To upgrade with Maven

To upgrade with Gradle 

Additionally, Apache Software Foundation has issued patches for Apache Tomcat versions 10.0.20, 9.0.62 and 8.5.78, in which the attack vector is closed on the Tomcat end.

Temporary workaround and mitigations

Organizations who are unable to update their applications and software to run the latest available version of the Spring Framework can temporarily mitigate this issue with the instructions below following the Spring temporary workaround. Spring suggests to do a careful update of the WebDataBinder DisallowedFields. 

In fact, if we take a look at WebDataBinder#doBind 

Blacklisted fields are never bound, they are simply removed. 

Additionally third-party firewalls can used for defense. Proper filtering applied to a WAF looking for the strings listed below can provide additional protection; however proper deployment is required to prevent an impact to standard business operations. The strings that can be utilized for a filter are: • class.* • Class.* • *.class.* • *.Class.*.

What the Cyber Fusion Center is doing

The Cyber Fusion Center is working to patch internal systems which may be impacted. The CFC will monitor firewall logs within the SIEM for activity related to this vulnerability. The CFC will also be able to leverage monitored Endpoint Detection and Response (EDR) systems to identify potential additional activity related to Spring4Shell.

References

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s