On March 29, 2022, ExtraHop's Threat Research team noticed social media chatter about a new remote code execution (RCE) vulnerability (a supply chain attack now officially confirmed as CVE-2022-22965) in the Spring Core Framework and began tracking the issue. Spring Core is a ubiquitous open-source framework for Java web application development, and commonly deployed along with Apache Tomcat servers. The impact of an RCE in this framework could have a serious impact similar to Log4Shell. Initial proof-of-concept (POC) snippets sporadically appeared on Twitter, but were often removed within a few minutes.
On March 30, 2022, ExtraHop reproduced the vulnerability and exploit by analyzing publicly available information and snippets of these alleged POCs. In this article, we share our findings with the broader security community and explain how this exploit works.
CVE-2022-22965 Technical Analysis
What is Parameter Binding in Spring Core?
During web application development, it is often useful to extract parameters from the request—including URIs, headers, and POST payloads—and access them programmatically.
Spring Core makes parameter extraction easy through the RequestMapping annotation. Below, we show you two methods for this functionality.
In the first method, you access parameters from a map of parsed key-value pairs, as shown in the following code example:
In this example, we define an email registration function that processes a GET request that registers email, username, and password parameters, stores the parameters in a model object called model.data, and echoes the key:value pairs from model.data in the HTTP response.
When this request is sent to a browser, the HTTP parameters are directly mapped as the corresponding email, username, and password variables. The values from these variables are concatenated into a string and stored in the model object, named model.data. As shown below, ultimately the data is printed to the browser.
In the second method, instead of accessing HTTP requests parameters as named method parameters in Java, you can map the parameters to properties in a regular Java object (often referred to as POJO or Plain Old Java Object), and then simply access the populated properties of that object, as shown in the following example:
In the above example, the email registration function processes the same GET request, but the parameters are bound to the properties of an object called MyTestObject.obj.
Now when we send the same request, we see that all of the parameters are directly mapped to MyTestObject's instance variables, which enables developers to access the data in the request by accessing properties of the object.
How to Identify the Spring4Shell Vulnerability
The vulnerability occurs when a special variable called class is exposed under certain conditions. One common condition is when a request parameter is bound to a POJO and the POJO is not decorated with the @RequestBody annotation. The class variable contains a reference to the POJO object that the HTTP parameters are mapped to. Attackers can specify the class variable in their requests, which enables them to directly access that object. While accessing the class variable itself does not lead to any security issue, attackers can also access all child properties of the class variable. And so by following chains of properties, attackers can access all sorts of other valuable objects on the system.
Although the Spring Core code contains the following logic to prevent accessing child properties of the class variable, the logic is not foolproof:
if (Class.class == beanClass &&
("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) {
continue;
}
The code checks for "class.classLoader" and "class.protectionDomain", but the logic can be bypassed with the following selector:
"class.module.classLoader"
As a result, this vulnerability is conceptually similar to CVE-2014-0094—an Apache Struts vulnerability that in the absence of proper block-listing and allow-listing—allows an attacker to get to the internal properties of Struts and a few others.
Spring4Shell Weaponization Techniques
The ability to access the class variable and all of its sub properties open a big door for attackers to change the behavior of the web application (such as remote code execution). Attackers are already familiar with many ways to exploit exposed class variables because of previous vulnerabilities with this exact beachhead, such as CVE-2014-0094. As a result, there are many existing weaponization techniques for this vulnerability.
For example, in Apache Tomcat, an attacker could access an AccessLogValve object from the class variable, by following the class.module.classLoader.resources.context.parent.pipeline.first path. A common way to weaponize this access is to redirect the access log to write a web shell into the webroot by manipulating different properties of the AccessLogValve object, including pattern, suffix, directory, and prefix. According to ExtraHop research, more than three-fourths of environments run Apache Tomcat.
In our POC, we tested this vulnerability against a web app running on an Apache Tomcat server with the following specifications:
Apache Tomcat: 9.0.60
JVM: 11.0.14.1+1
Spring: 5.2.4.RELEASE
By manipulating the AccessLogValve object through the method described above, we were able to inject a web shell into the app. The following screenshot shows us running the "cat /etc/passwd" command through the webshell:
Spring Core has officially confirmed and patched this vulnerability as of 3/31/2022 morning. Please refer to the official blog for patching instructions. ExtraHop R&D has developed and deployed Spring4Shell detection and threat hunting capabilities for this vulnerability to our customers, based on this research.
On-demand Reveal(x) Demo: Stop a Log4Shell JNDI Injection Attempt