Cisco SMA 暴露面检测工具 - 快速识别CVE-2025-20393风险

10 阅读5分钟

Cisco SMA 暴露面检测工具

项目概述

这是一个轻量级、单文件的 Python 3 安全检测脚本,专为快速识别 Cisco Secure Email 和 Secure Malware Analytics 设备的潜在攻击暴露面而设计。它通过扫描特定端口、执行 HTTP/S 指纹识别以及匹配已知的恶意软件模式,帮助安全团队高效地评估目标系统是否受到 CVE-2025-20393 等漏洞的威胁。该工具无需安装任何外部依赖,开箱即用。

功能特性

  • 多端口并发扫描:快速检测目标主机上的关键端口,包括管理端口(443, 8080)、隔离区专用端口(6025)以及共享端口(82, 83, 8443, 9443)。
  • 智能指纹识别:对开放端口发起 HTTP/HTTPS 请求,分析响应头中的 Server 字段、HTTP 状态码、重定向位置及认证领域(WWW-Authenticate),以精确识别 Cisco 设备。
  • Cisco 专有路径探测:自动尝试访问 /quarantine, /spamquarantine, /spam, /sma-login, /login 等常见隔离区管理路径,进一步验证服务类型。
  • 版本信息提取:通过正则表达式从响应内容中匹配 asyncos 等关键词,尝试提取设备的固件版本号。
  • 恶意软件 IOC 检测:在 HTTP 响应及原始 Socket Banner 中搜索 "AquaShell", "AquaTunnel", "Chisel", "AquaPurge" 等已知恶意软件模式,提供初步的入侵指标。
  • 灵活的 DNS 解析:支持输入域名(自动解析为 IP)或直接输入 IP 地址进行扫描。
  • 详细的调试输出:通过 -v 参数启用详细模式,可查看所有执行的操作步骤,便于深入分析。

安装指南

系统要求

  • Python 版本: 3.6 或更高版本。
  • 依赖项: 无需安装任何第三方库,仅使用 Python 标准库(argparse, http.client, json, re, socket, ssl, sys, concurrent.futures)。

安装步骤

  1. 将脚本文件(例如 cisco-sma-scanner.py)下载或复制到您的本地机器。
  2. 为脚本添加可执行权限(可选):
    chmod +x cisco-sma-scanner.py
    

使用说明

基础用法

在终端中,使用 Python 解释器运行脚本,并指定要扫描的目标主机(域名或 IP 地址)。

python3 cisco-sma-scanner.py example.com

常用示例

  1. 扫描单个 IP 地址并显示详细输出: 如果您想绕过 DNS 解析并查看所有检查步骤,可以使用 -v 参数。

    python3 cisco-sma-scanner.py -v 192.168.1.100
    
  2. 自定义超时时间: 在网络状况不佳的环境中,可以增加超时时间(以秒为单位)。

    python3 cisco-sma-scanner.py -t 5 example.com
    
  3. 完整命令示例: 结合所有常用选项进行深度扫描。

    python3 cisco-sma-scanner.py -v -t 3 mail.cisco-target.com
    

输出解读

脚本输出将清晰展示:

  • 目标主机及其解析后的 IP 地址。
  • 所有开放的管理和隔离端口列表。
  • 对于每个开放端口,提供详细的指纹信息,包括:
    • HTTP 状态码和服务器 banner。
    • 是否检测到 Cisco 专有路径。
    • 是否匹配到恶意软件特征码(IOC)。
    • 从响应内容中提取的设备版本号。

核心代码

1. 并发端口扫描器

使用 ThreadPoolExecutor 实现高效的并发端口扫描,显著提升扫描速度。

def scan_ports(
    host: str, ports: Iterable[int], timeout: float = 3.0, max_workers: int = 10, verbose: bool = False
) -> List[int]:
    """
    并发扫描指定主机的端口列表,返回所有开放端口。
    
    Args:
        host: 目标主机IP。
        ports: 要扫描的端口列表。
        timeout: 连接超时时间。
        max_workers: 最大并发线程数。
        verbose: 是否打印详细日志。
    
    Returns:
        包含所有开放端口的列表。
    """
    unique_ports = sorted(set(int(p) for p in ports))
    if not unique_ports:
        return []

    worker_count = max(1, min(max_workers, len(unique_ports)))
    open_ports = []
    
    with ThreadPoolExecutor(max_workers=worker_count) as executor:
        # 提交所有扫描任务
        futures = {executor.submit(is_port_open, host, port, timeout): port 
                   for port in unique_ports}
        
        # 收集结果
        for future in futures:
            port = futures[future]
            if future.result():
                vprint(verbose, f"  [+] Port {port} is open")
                open_ports.append(port)
            else:
                vprint(verbose, f"  [-] Port {port} is closed/filtered")
                
    return sorted(open_ports)

def is_port_open(host: str, port: int, timeout: float = 3.0) -> bool:
    """检查单个端口是否开放。"""
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except OSError:
        return False

2. 目标解析与验证

健壮的输入处理,支持域名自动解析为 IP 地址,并提供清晰的错误反馈。

def resolve_target(target: str) -> Tuple[str, str]:
    """
    解析目标地址,返回原始目标及其第一个解析到的 IP 地址。
    
    此函数是脚本的入口点,负责处理用户输入的域名或 IP,
    并确保目标可达。
    
    Args:
        target: 用户输入的目标字符串(域名或IP)。
    
    Returns:
        一个包含 (原始目标, 解析后IP) 的元组。
    
    Raises:
        ValueError: 如果目标为空或无法解析。
    """
    host = target.strip()
    if not host:
        raise ValueError("Target cannot be empty")

    try:
        # 获取地址信息,取第一个返回的IP
        addrinfo = socket.getaddrinfo(host, None)[0]
        ip_address = addrinfo[4][0]
        print(f"[*] Resolved {host} to {ip_address}")
        return host, ip_address
    except socket.gaierror as exc:
        raise ValueError(f"Could not resolve {host}: {exc}") from exc

3. HTTP 指纹识别逻辑(片段)

通过对开放端口发起 HTTP/HTTPS 请求,并结合关键词匹配来识别 Cisco 设备。

# 核心的指纹识别函数(示例片段,展示核心逻辑)
def fingerprint_service(host, port, verbose):
    """
    对目标端口进行HTTP指纹识别,查找Cisco特有标识。
    
    此函数尝试建立SSL连接(对于443等端口),发送HTTP请求,
    并分析响应头及正文,判断是否为Cisco设备。
    """
    # 判断是否使用HTTPS
    use_https = port in [443, 8443, 9443]
    paths_to_try = ["/", "/quarantine", "/spamquarantine"]
    
    for path in paths_to_try:
        try:
            conn = None
            if use_https:
                # 创建HTTPS连接,忽略证书错误以进行探测
                context = ssl.create_default_context()
                context.check_hostname = False
                context.verify_mode = ssl.CERT_NONE
                conn = http.client.HTTPSConnection(host, port, timeout=5, context=context)
            else:
                conn = http.client.HTTPConnection(host, port, timeout=5)
            
            # 发送GET请求
            conn.request("GET", path, headers={"User-Agent": "Cisco-SMA-Checker/1.0"})
            response = conn.getresponse()
            
            # 读取部分响应内容用于关键词匹配
            data = response.read(2048).decode('utf-8', errors='ignore')
            
            # 检查Cisco特有关键词
            if any(keyword in response.getheader('Server', '') or keyword in data 
                   for keyword in BODY_KEYWORDS):
                print(f"  [!] Found Cisco signature on {host}:{port}{path}")
                
            # 检查版本信息
            for pattern in VERSION_PATTERNS:
                match = re.search(pattern, data, re.IGNORECASE)
                if match:
                    print(f"  [Version] Detected version: {match.group(1)}")
                    
        except Exception as e:
            vprint(verbose, f"  [Error] Failed to probe {host}:{port}{path}: {e}")
        finally:
            if conn:
                conn.close()
```FINISHED
6HFtX5dABrKlqXeO5PUv/yVlbVlaGbYnAomM0Kw+s18cg18sqyRYcn9cnRK0HP6W