IngressNightmare批量安全检测工具 - CVE-2025-1974漏洞利用验证脚本

IngressNightmare 批量安全检测工具

CVE-2025-1974 (IngressNightmare) 漏洞利用验证脚本

一个专为安全研究人员和运维团队设计的Python自动化工具,用于批量检测CVE-2025-1974 IngressNightmare漏洞。该工具通过发送构造的JSON payload到目标IP列表,自动收集响应并生成结构化的XML报告,极大提升了漏洞验证效率。

:sparkles: 功能特性

  • 批量并发检测:支持从文件中读取大量IP地址,自动化顺序发送HTTPS请求
  • 智能响应分类:基于HTTP状态码和curl返回码自动将请求分类为成功、失败、超时或错误
  • 双报告输出:分别生成成功请求XML报告和失败请求XML报告,便于后续分析和漏洞确认
  • 进度条清理:自动过滤curl输出的进度信息,保留纯净的错误和调试日志
  • 灵活配置:支持自定义JSON payload文件、目标端口、请求超时、请求间隔延迟等参数
  • 详细日志输出:实时显示每个IP的请求状态、HTTP响应码和错误信息,便于现场调试
  • 零依赖设计:仅依赖Python标准库和系统curl命令,无需额外安装第三方包

:package: 安装指南

系统要求

  • Python 3.6 或更高版本
  • curl 命令行工具 (通常Linux/macOS预装,Windows需单独安装)
  • 网络访问权限(需能访问目标IP的HTTPS端口)

安装步骤

  1. 克隆代码仓库
git clone https://github.com/abrewer251/CVE-2025-1974_IngressNightmare_PoC.git
cd CVE-2025-1974_IngressNightmare_PoC
  1. 赋予脚本执行权限 (Linux/macOS)
chmod +x poc.py
  1. 准备IP列表文件

创建一个文本文件,每行一个目标IP地址:

echo "192.168.1.10" > ips.txt
echo "192.168.1.20" >> ips.txt
  1. 准备JSON Payload文件 (默认为 poc.json)

根据CVE-2025-1974漏洞特性构造对应的JSON请求体,保存为 poc.json

:rocket: 使用说明

基础用法

python3 poc.py ips.txt

使用默认配置:读取 ips.txt 中的IP列表,发送 poc.json payload到端口 8443,超时时间15秒,请求间隔1秒,生成 4-3_Success.xml4-3_Failure.xml 报告。

命令行参数

参数 简写 说明 默认值
--json -j JSON payload文件路径 poc.json
--port -p 目标HTTPS端口 8443
--timeout -t 每个请求超时时间(秒) 15
--delay -d 请求间延迟时间(秒) 1.0
--success -s 成功报告文件名 4-3_Success.xml
--failure -f 失败报告文件名 4-3_Failure.xml
--help -h 显示帮助信息

典型使用场景

场景一:自定义Payload和端口

python3 poc.py -j custom_payload.json -p 9443 ips.txt

场景二:快速扫描模式 (缩短超时和延迟)

python3 poc.py -t 5 -d 0.5 ips.txt

场景三:自定义输出报告名称

python3 poc.py -s success_scan.xml -f failed_scan.xml ips.txt

场景四:大规模IP列表扫描 (使用较慢间隔避免被限制)

python3 poc.py -d 3.0 -t 30 ip_list_large.txt

输出示例

控制台实时输出:

[INFO] Processing IP: 192.168.1.10
[SUCCESS] IP: 192.168.1.10 | HTTP Code: 200
[INFO] Processing IP: 192.168.1.20
[FAILED] IP: 192.168.1.20 | HTTP Code: 405
[INFO] Processing IP: 192.168.1.30
[TIMEOUT] IP: 192.168.1.30 | Request timed out

生成的XML报告文件包含每个请求的详细数据:IP地址、状态、HTTP状态码、响应体、stderr日志和执行的curl命令。

:laptop: 核心代码

1. curl请求执行与响应捕获

def run_curl(ip, json_file, port, timeout):
    """
    执行curl命令向目标IP发送JSON payload并捕获响应
    
    核心功能:
    - 构建HTTPS URL: https://{ip}:{port}
    - 使用curl发送POST请求,包含JSON文件内容
    - 捕获HTTP状态码(通过-w %{http_code})
    - 分离响应体和状态码(响应体末尾三位为状态码)
    - 清理stderr中的进度信息(保留错误日志)
    - 处理超时异常并返回统一格式的字典
    
    参数:
        ip: 目标IP地址
        json_file: JSON payload文件路径
        port: 目标端口
        timeout: 请求超时时间(秒)
    
    返回:
        dict: 包含ip、status、stdout、stderr、returncode、http_code、command
    """
    url = f"https://{ip}:{port}"
    curl_command = [
        "curl",
        "--insecure",      # 忽略SSL证书验证(测试环境)
        "-k",              # 等同于--insecure
        "-v",              # 详细输出模式,便于调试
        "-w", "%{http_code}",  # 在输出末尾追加HTTP状态码
        "-H", "Content-Type: application/json",  # 设置JSON Content-Type
        "--data", f"@{json_file}",  # 从文件读取JSON数据
        url
    ]

    try:
        result = subprocess.run(
            curl_command,
            capture_output=True,
            text=True,
            timeout=timeout
        )

        full_output = result.stdout
        http_code = full_output[-3:] if len(full_output) >= 3 else "000"
        response_body = full_output[:-3].strip() + "\n"

        # 分类逻辑:返回码为0且HTTP状态码不等于405(Method Not Allowed)视为成功
        status = "success" if result.returncode == 0 and http_code != "405" else "failed"

        return {
            "ip": ip,
            "status": status,
            "stdout": response_body,
            "stderr": clean_stderr(result.stderr),  # 清理进度信息
            "returncode": result.returncode,
            "http_code": http_code,
            "command": " ".join(curl_command)
        }

    except subprocess.TimeoutExpired:
        return {
            "ip": ip,
            "status": "timeout",
            "stdout": "",
            "stderr": "Request timed out\n",
            "returncode": None,
            "http_code": "000",
        }

2. curl输出清理函数

def clean_stderr(stderr_text):
    """
    清理curl的stderr输出,移除进度表和速度信息
    
    功能说明:
    - 使用正则表达式匹配并移除curl的进度百分比行
    - 移除包含"Dload Upload Total Spent Left Speed"的标题行
    - 保留错误信息、警告和调试输出
    
    正则说明:
    - progress_pattern: 匹配进度百分比行,如 "  % Total    % Received ..."
    - skip_line: 匹配速度标题行,完全匹配"Dload Upload Total Spent Left Speed"
    
    参数:
        stderr_text: curl的原始stderr输出
    
    返回:
        str: 清理后的stderr内容,末尾添加换行符
    """
    lines = stderr_text.splitlines()
    cleaned_lines = []

    progress_pattern = re.compile(r"\s*% Total\s+% Received.*|^\s*\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+.*")
    skip_line = re.compile(r"Dload\s+Upload\s+Total\s+Spent\s+Left\s+Speed")

    for line in lines:
        if not progress_pattern.match(line.strip()) and not skip_line.match(line.strip()):
            cleaned_lines.append(line)

    return "\n".join(cleaned_lines).strip() + "\n"

3. XML报告生成器

def generate_xml_report(results, output_file, report_type):
    """
    生成XML格式的详细报告文件
    
    功能说明:
    - 创建符合标准XML格式的报告
    - 包含每个请求的完整元数据:IP、状态、HTTP状态码、返回码、响应体、stderr、curl命令
    - 使用CDATA块包裹特殊字符,确保XML合法性
    - 自动在根节点下添加成功或失败的分类
    
    参数:
        results: 请求结果字典列表
        output_file: 输出XML文件路径
        report_type: 报告类型(用于根节点命名)
    
    XML结构:
        <IngressNightmare>
            <{report_type}>
                <Request>
                    <IP>192.168.1.1</IP>
                    <Status>success</Status>
                    <HTTP_Code>200</HTTP_Code>
                    <ReturnCode>0</ReturnCode>
                    <Stdout><![CDATA[...]]></Stdout>
                    <Stderr><![CDATA[...]]></Stderr>
                    <Command><![CDATA[...]]></Command>
                </Request>
            </{report_type}>
        </IngressNightmare>
    """
    root = ET.Element("IngressNightmare")
    type_elem = ET.SubElement(root, report_type)
    
    for res in results:
        req_elem = ET.SubElement(type_elem, "Request")
        
        # 添加每个字段到XML节点
        ip_elem = ET.SubElement(req_elem, "IP")
        ip_elem.text = res["ip"]
        
        status_elem = ET.SubElement(req_elem, "Status")
        status_elem.text = res["status"]
        
        http_code_elem = ET.SubElement(req_elem, "HTTP_Code")
        http_code_elem.text = res["http_code"]
        
        returncode_elem = ET.SubElement(req_elem, "ReturnCode")
        returncode_elem.text = str(res["returncode"]) if res["returncode"] is not None else "None"
        
        # 使用CDATA保留特殊字符
        stdout_elem = ET.SubElement(req_elem, "Stdout")
        stdout_elem.text = ET.CDATA(res["stdout"]) if res["stdout"] else ""
        
        stderr_elem = ET.SubElement(req_elem, "Stderr")
        stderr_elem.text = ET.CDATA(res["stderr"]) if res["stderr"] else ""
        
        command_elem = ET.SubElement(req_elem, "Command")
        command_elem.text = ET.CDATA(res["command"])
    
    tree = ET.ElementTree(root)
    ET.indent(tree, space="  ", level=0)  # Python 3.9+ 格式化输出
    tree.write(output_file, encoding="utf-8", xml_declaration=True)

该工具仅供安全研究和授权测试使用,请在遵守当地法律法规的前提下运行。
6HFtX5dABrKlqXeO5PUv/0dvXZ3Wu5ra76/yvJK4cgDsSrZ4GOh0xdw32tRHi65AR+gJterSJ1a5DajvLlcXdw==

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容