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)。
安装步骤
-
将脚本文件(例如
cisco-sma-scanner.py)下载或复制到您的本地机器。 -
为脚本添加可执行权限(可选):
bashchmod +x cisco-sma-scanner.py
使用说明
基础用法
在终端中,使用 Python 解释器运行脚本,并指定要扫描的目标主机(域名或 IP 地址)。
bash
python3 cisco-sma-scanner.py example.com
常用示例
-
扫描单个 IP 地址并显示详细输出 : 如果您想绕过 DNS 解析并查看所有检查步骤,可以使用
-v参数。bashpython3 cisco-sma-scanner.py -v 192.168.1.100 -
自定义超时时间: 在网络状况不佳的环境中,可以增加超时时间(以秒为单位)。
bashpython3 cisco-sma-scanner.py -t 5 example.com -
完整命令示例: 结合所有常用选项进行深度扫描。
bashpython3 cisco-sma-scanner.py -v -t 3 mail.cisco-target.com
输出解读
脚本输出将清晰展示:
- 目标主机及其解析后的 IP 地址。
- 所有开放的管理和隔离端口列表。
- 对于每个开放端口,提供详细的指纹信息,包括:
- HTTP 状态码和服务器 banner。
- 是否检测到 Cisco 专有路径。
- 是否匹配到恶意软件特征码(IOC)。
- 从响应内容中提取的设备版本号。
核心代码
1. 并发端口扫描器
使用 ThreadPoolExecutor 实现高效的并发端口扫描,显著提升扫描速度。
python
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 地址,并提供清晰的错误反馈。
python
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 设备。
python
# 核心的指纹识别函数(示例片段,展示核心逻辑)
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