Alisha-chaudhary/ssh-enum
GitHub: Alisha-chaudhary/ssh-enum
通过统计分析方法在现代 OpenSSH 环境上重新验证 CVE-2016-6210 计时旁路侧信道,并构建配套的攻击模拟与检测工具链的安全研究项目。
Stars: 0 | Forks: 0
# ssh-enum
## CVE-2016-6210 统计验证研究
*使用统计分析对 OpenSSH 用户名枚举进行可重复的重新调查。*
本项目重新调查了 **CVE-2016-6210**(一种已公开的 OpenSSH 计时旁路侧信道),以确定在采用默认 PAM 配置的现代 Ubuntu Server 上,它是否仍然可以被观测到。
该项目没有直接假设已公开的行为依然适用,而是通过手动探测、Hydra 和 Metasploit 收集身份验证计时测量数据,并使用 **Welch's t-test** 和 **Cohen's d** 评估这些数据,以将真实的计时信号与测量噪声区分开来。
研究在受测试的默认配置中**未发现具有统计学意义的计时差异**,这证明了可重复实验以及对已发布安全声明进行基于证据的验证的价值。
⚠️ **法律声明**
本项目完全在自有的、隔离的实验室环境中进行。所有发现仅适用于受测试的配置。切勿对您不拥有或未获得明确书面授权的系统进行测试。
## 目录
- [问题描述](#-problem-statement)
- [实验室设置](#-lab-setup)
- [方法论](#-methodology)
- [构建内容](#️-what-was-built)
- [观察与发现](#-observations--findings)
- [思考过程](#-thought-process)
- [安全风险](#-security-risks)
- [缓解策略](#-mitigation-strategies)
- [未来增强](#-future-enhancements)
- [项目结构](#-project-structure)
- [快速开始](#-quick-start)
- [参考](#-references)
## 🎯 问题描述
**用户枚举** - 即在没有有效凭据的情况下,确定特定用户名是否存在于远程系统上的能力。这是导致账户沦陷的攻击链中至关重要的第一步:
```
Reconnaissance → [User Enumeration] → Password Attack → Access
↑
This project investigates here
```
如果攻击者能够通过分析服务器响应来区分“该用户存在”和“该用户不存在”,他们就能大幅缩小后续暴力破解或撞库攻击的密钥空间。
SSH 经常成为攻击目标,因为它几乎被普遍暴露,处理密码身份验证,并且较旧的实现在有效和无效用户名之间存在可测量的计时差异 (CVE-2016-6210)。
**本次调查提出了两个问题:**
1. 采用默认配置的现代 OpenSSH 在 Ubuntu 22.04.5 LTS 上,是否会通过响应消息、计时或工具报告的信号泄露用户名的存在?
2. 如果攻击者无论如何都进行了尝试,它会留下什么痕迹?以及这些痕迹能被多可靠地检测到?
## 🖥️ 实验室设置
所有测试均在完全隔离的、仅主机的虚拟网络中执行,没有互联网暴露。
| 机器 | 操作系统 | 角色 | IP | SSH 版本 |
|----------|---------------------------|-----------------------------------------|------------------|------------------|
| 攻击者 | Kali Linux 2024.1 | 进攻性工具、分析脚本 | 192.168.56.5 | — |
| 目标 | Ubuntu Server 22.04.5 LTS | 运行采用**默认**配置的 OpenSSH | 192.168.56.10 | OpenSSH 8.9p1 |
**目标 SSH 配置(`/etc/ssh/sshd_config` 默认值):**
```
PasswordAuthentication yes
UsePAM yes # Key setting — normalises timing via dummy hash
PermitRootLogin prohibit-password
MaxAuthTries 6
LogLevel INFO
```
`UsePAM yes` 是关键的加固设置。它强制 OpenSSH 为不存在的用户运行虚假的 bcrypt 计算,以匹配真实密码检查的计时。
引入此设置专门是为了作为针对 CVE-2016-6210 的对策。
## 🔬 方法论
每种攻击方法都作为具有干净日志状态的独立试验运行:
```
# 每次试验前重置 target 的 log 状态
sudo truncate -s 0 /var/log/auth.log
# 攻击之后:收集证据
sudo cp /var/log/auth.log ~/evidence/trial-N-auth.log
```
每次试验收集的证据:
- 工具 stdout/stderr(原样保存)
- 来自目标的 `/var/log/auth.log`
- 通过 `manual_ssh.py` 中的 `time.perf_counter()` 获取的响应计时样本
- 在进行任何身份验证之前获取的 SSH banner
### 攻击方法
| 方法 | 工具 | 字典表 | 目的 |
|-----------------------|--------------------------------------|-------------------------|-------------------------------------------------|
| 手动 SSH | `ssh` CLI + Paramiko | 50 个常见用户名 | 基线;检查原始响应 |
| Hydra 暴力破解 | `hydra` | 同上 50 个 | 自动化;利用 Hydra 内置的枚举模式 |
| Metasploit 模块 | `auxiliary/scanner/ssh/ssh_enumuser` | 同上 50 个 | 框架的专用枚举模块 |
| Banner 指纹识别 | 自定义 `BannerFingerprinter` | N/A | 无需身份验证的版本泄露,CVE 检查 |
| 计时分析 | 自定义 `ResponseAnalyzer` | 有效 vs 无效子集 | 统计旁路侧信道检查 |
## 构建内容
本项目不仅仅是运行工具——它将每个攻击和所有检测逻辑封装在结构化的 Python 代码库中,并提供了一个可端到端运行整个流水线的编排器。
### 攻击工具 (`src/attack_tools/`)
**`ManualSSHEnumerator`** — 使用 `paramiko` 对每个用户名测试 N 次,记录精确的计时、结果类型和 SSH banner。计算每个用户名的平均值/标准差。至关重要的是,它在尝试之间**不**重用连接,确保每个样本都捕获完整的服务器端处理时间。
**`BannerFingerprinter`** — 通过原始 TCP socket 抓取 SSH banner(无需凭据)。解析实现名称、版本字符串和操作系统提示。与本地 CVE 注册表进行交叉引用。像 `OpenSSH_8.9p1 Ubuntu-3ubuntu0.6` 这样的版本会暴露确切的服务器软件——这可能足以在任何身份验证尝试之前识别已知的漏洞。
**`HydraAutomation`** — Hydra 的子进程封装器。解析 stdout 以提取成功的登录、错误消息以及 Hydra 自己的枚举结论(`does not support user enumeration`)。
**`MetasploitScanner`** — 编写临时资源脚本并通过子进程驱动 `msfconsole`。解析输出以检测安全加固和发现的任何用户名。
### 检测工具 (`src/detection_tools/`)
**`LogParser`** — 基于正则表达式的 auth.log 解析器,支持五种 SSH 事件类型:`failed_invalid_user`、`failed_valid_user`、`pre_auth_reject`、`accepted`、`disconnected`。返回包含时间戳、事件类型、用户名、源 IP 和端口的结构化事件字典。
**`ResponseAnalyzer`** — 对来自有效与无效用户名的计时分布执行 Welch's t-test。计算计时差值 (ms)、p-value、Cohen's d 效应量以及通俗易懂的结论。阈值:差值 ≥ 5ms 且 p < 0.05 触发旁路侧信道警告。
**`EnumerationDetector`** — 四种检测模式:
- **快速用户探测**:滑动窗口 - 同一 IP,在 60s 内探测 ≥10 个不同的用户名
- **字典表相关性**:尝试的用户名与已知攻击列表之间的匹配率
- **序列计时**:尝试间隙的变异系数(低 CoV → 工具)
- **分布式探测**:来自多个 IP 的相同用户名(撞库侦察)
**`AlertingSystem`** — 轻量级警报发射器。向 stdout 生成带有时间戳的 JSON 警报。可根据需要扩展 email/SIEM/webhook 集成。
### 编排器
**`run_investigation.py`** — CLI 驱动程序,按顺序运行所有四个阶段,并将结果写入 `data/results/`。运行 `--help` 获取完整用法。
```
python run_investigation.py \
-target 192.168.xx.xxxx \
-usernames data/wordlists/common-usernames-50.txt \
-log data/sample-logs/auth.log \
-known-valid root ubuntu \
-samples 10
```
## 观察与发现
### 发现 1:响应一致性 — 核心防御
**测试假设:** 对于不存在的用户,OpenSSH 是否会返回与密码错误的现有用户不同的错误消息?
```
# 不存在的用户
$ ssh ghost_user_999@192.168.xx.xxxx
Permission denied (publickey,password).
# 现有用户,密码错误
$ ssh root@192.168.xx.xxxx
Permission denied (publickey,password).
```
**结果:** 响应是逐字节相同的。协议没有泄露任何信息。
**原因:** 自 OpenSSH 7.3 起,`UsePAM yes` 强制服务器为不存在的用户运行一次虚假的 `crypt()` 操作,从而匹配真实身份验证失败时的计时和错误路径。此修复是对 CVE-2016-6210 的直接响应。
### 发现 2:未检测到计时旁路侧信道
**测试假设:** 即使错误消息匹配,在有效和无效用户名之间是否存在可以利用统计数据挖掘的、可测量的计时差异?
对 50 个用户名中的每一个收集了十个计时样本。已知有效的用户(从系统确认)与无效用户池进行了比较。
| 指标 | 值 |
|-----------------------------|-------------------------------------|
| 平均计时 — 无效用户 | ~312 ms |
| 平均计时 — 有效用户 | ~311 ms |
| 差值 | **~1 ms** |
| Welch's t-test p-value | > 0.40 |
| 结论 | **无法区分的旁路侧信道** |
~1ms 的差值远低于 5ms 的噪声阈值,且不具有统计学意义(p >> 0.05)。OpenSSH 的虚假哈希计算是有效的。
### 发现 3:Hydra 报告不支持枚举
Hydra 的 SSH 枚举模式依赖于三个信号之一:不同的错误消息、不同的计时或不同的连接行为。由于这三个信号都被归一化了,Hydra 明确报告:
```
[ERROR] target ssh://192.168.56.10:22/ does not support user enumeration
[STATUS] 50/50 tries completed, 0 valid logins found
```
**观察到的副作用:** 尽管枚举失败,但所有 50 次尝试都被记录在 `/var/log/auth.log` 中,包括源 IP、时间戳和尝试的用户名。攻击者的存在暴露无遗。
### 发现 4:Metasploit 在完成扫描前检测到了安全加固
`auxiliary/scanner/ssh/ssh_enumuser` 模块会在尝试枚举之前从 banner 中检查 OpenSSH 版本。版本 ≥ 7.3 且设置了 `UsePAM yes` 会被标记为已加固,模块将提前退出:
```
[*] 192.168.xx.xxxx:22 - SSH - Checking for vulnerability
[*] 192.168.xx.xxxx:22 - SSH - Target is not vulnerable: OpenSSH 8.9p1 (hardened)
```
这是一个有用的发现:在进行任何枚举尝试之前,仅 banner 就能向攻击者传达服务器的防御姿态。
### 发现 5:即使枚举失败,检测依然可靠
从防御者的角度来看,这是一个关键的洞察:**即使攻击没有成功,也会产生噪声**。所有四种检测模式都针对收集到的 auth.log 正确触发:
| 检测 | 触发器 | 严重性 |
|----------------------|-----------------------------------------------|----------|
| 快速用户探测 | Kali IP 在 <60s 内探测了 50 个用户名 | 高 |
| 字典表相关性 | 48/50 尝试的名称与字典表匹配 | 高 |
| 序列计时 | 尝试间隙 CoV = 0.04(工具特征) | 中 |
| 仅 Banner 探测 | 发送任何用户名前认证前断开连接 | 低 |
## 思考过程
### 为什么先进行手动 SSH 枚举?
从手动测试开始的本能在方法论上是合理的:在信任工具输出之前,您需要了解原始协议实际说了什么。运行 `ssh ghost@target` 并观察确切的错误消息,可以告诉您在投入时间进行自动化之前,是否*有东西*需要枚举。
第一个观察结果是,无论用户是否存在,`Permission denied (publickey,password)` 看起来都是一样的,这是核心发现。随后的所有工作都是对该结果的验证。
### 所做的假设(以及重新审视)
最初的假设是 Hydra 和 Metasploit 会比手动测试*更*强大,因此如果手动失败了,工具可能仍然会成功。事实证明这在预期的方向上是错误的,但在*原因*上却是正确的:工具在这里并没有增加能力,因为协议本身并没有泄露信号。工具只是基于同一协议的自动化。
第二个值得探讨的假设:第一次手动尝试明显比随后的尝试慢,而成功密码的尝试很快。这最初被解释为潜在的计时信号。经过反思,这种减速是全新网络状态下 TCP 连接建立的开销(ARP 解析、连接建立),而不是服务器端的处理时间。控制这一点——通过在 TCP 握手*之后*通过 `time.perf_counter()` 进行测量,或者丢弃第一个样本——会更加严谨。`ManualSSHEnumerator` 的实现通过收集每个用户名 10 个样本并报告平均值/标准差来解决这个问题,这稀释了第一个样本的噪声。
### 项目期间发生的变化
最初的范围很窄:运行三个工具,记录它们是否有效。项目在两个方向上发生了演变:
**向内(更深入的分析):** 当初步结果呈阴性时,自然的问题就变成了*为什么*——这促使我们去阅读 OpenSSH 更新日志、CVE-2016-6210 和 `UsePAM` 的实现。了解机制比仅仅记录结果更有价值。
**向外(检测转换):** 阴性的攻击结果仍然是有用的防御数据点。转向“即使枚举失败了,服务器看到了什么?”这个问题,促成了日志分析和检测工程组件的开发,这将一个一维的运行工具练习变成了一项双向的调查。
### 如果重来会有不同的做法
计时测量是在仅主机的虚拟网络上进行的,这比真实网络引入的抖动更少,但也意味着结果是乐观的。在具有 TCP 延迟、抖动和重传的真实环境中,噪声基准会更高,计时分析将需要每个用户名提供更多的样本。更稳健的方法论将在模拟的 WAN 链路上进行测试(使用 `tc netem` 引入受控的延迟和抖动),以查看结论在现实条件下是否依然成立。
## 安全风险
即使在本次实验中枚举没有成功,攻击面和相关风险依然存在:
**如果枚举是*可能*的(例如,旧版 OpenSSH、`UsePAM no`、自定义 PAM 栈):**
- 攻击者可以将暴力破解活动缩小到仅针对已确认有效的用户名,从而大幅降低检测风险并提高效率。
- 结合密码喷洒(对所有有效用户使用一个常见密码),这可以绕过基于单用户锁定的 `MaxAuthTries`。
**即使具有枚举抵抗力,依然存在的风险:**
- SSH banner 泄露了确切的 OpenSSH 版本和操作系统。看到 `OpenSSH_8.9p1` 的攻击者可以在发送任何身份验证数据包之前,立即检查 CVE-2024-6387 (regreSSHion) 是否适用。
- 所有枚举尝试都会记录源 IP。如果缺乏日志监控,缓慢消耗式攻击(每小时尝试一次)可以探测数千个用户名,而不会触发基于速率的警报。
- 即使枚举不可行,`PasswordAuthentication yes` 也会使基于密码的攻击面保持开放。OSINT 之后的凭据攻击(使用泄露的密码列表针对通过 OSINT 获取的用户名)根本不需要服务器端枚举。
## 缓解策略
| 威胁 | 缓解措施 | 所需配置更改 |
|---------------------------|------------------------------------------------------------------|-------------------------------------------|
| 计时旁路侧信道 | 确保设置 `UsePAM yes`(Ubuntu 默认) | 无 — 已是默认值 |
| Banner 版本泄露 | 在 `sshd_config` 中设置 `VersionAddendum none` 和 `DebianBanner no` | 是 |
| 基于密码的攻击 | `PasswordAuthentication no` — 仅密钥认证 | 是 |
| OSINT 后的暴力破解 | `fail2ban` 与 `sshd` jail 结合 | 安装 + 配置 |
| 缓慢消耗式枚举 | 将日志发送至 SIEM;对 >N 个不同用户名/IP/小时发出警报 | 需要 SIEM |
| Root 登录 | `PermitRootLogin no` | 是(默认为 `prohibit-password`) |
| 认证前断开连接 | `MaxStartups 10:30:60` 对未经验证的连接进行速率限制 | 是 |
**针对强化部署推荐的最低限度 `sshd_config` 新增项:**
```
PasswordAuthentication no
PermitRootLogin no
MaxAuthTries 3
MaxStartups 10:30:60
VersionAddendum none
LogLevel VERBOSE
```
## 未来增强
当前项目测试了一种配置中的一种协议。自然的扩展方向:
**枚举同一主机上的其他服务。** SMTP (`VRFY`/`EXPN`)、LDAP(属性查询)、HTTP 登录表单和 SNMP 都是在 SSH 加固的同一台机器上常见的用户名泄露向量。跨服务的对比研究将产生更完整的风险图景。
**测试非默认的 SSH 配置。** `UsePAM no`、自定义 PAM 模块、Kerberos 身份验证后端以及旧版 OpenSSH 版本(部署在嵌入式系统、网络设备中)可能仍然存在计时泄露。针对故意配置不当的环境测试同一流水线将展示这种对比。
**使用 inotify 进行实时检测。** 目前的检测是针对副本日志文件进行的事后分析。生产级的版本将使用 `inotify`(或 `tail -f` + 解析器线程)在枚举尝试开始后的几秒钟内进行近乎实时的检测和警报。
**网络层检测。** Auth.log 是一种基于主机的痕迹。使用数据包级别的检测来补充它:在完成身份验证握手之前关闭的到 22 端口的短暂 TCP 连接是仅进行 banner 指纹识别的特征。这可以实现为 `Zeek` 或 `Suricata` 规则。
**用于统计报告的 Jupyter notebooks。** 收集到的计时数据易于可视化——每个用户名计时分布的箱线图、随时间变化的尝试频率散点图、源 IP 的热图。Notebooks 将使分析具有可重复性和可共享性。
## 项目结构
```
ssh-enumeration-analysis/
│
├── README.md
├── run_investigation.py ← Full pipeline orchestrator (start here)
├── requirements.txt
│
├── src/
│ ├── attack_tools/
│ │ ├── __init__.py
│ │ ├── manual_ssh.py ← Paramiko-based timing probe
│ │ ├── banner_fingerprinter.py ← No-auth banner grab + CVE lookup
│ │ ├── hydra_automation.py ← Hydra subprocess wrapper
│ │ └── metasploit_scanner.py ← MSF console automation
│ │
│ └── detection_tools/
│ ├── __init__.py
│ ├── log_parser.py ← auth.log regex parser
│ ├── response_analyzer.py ← Welch t-test + Cohen's d
│ ├── pattern_detector.py ← 4 detection patterns
│ └── alerting_system.py ← JSON alert emitter
│
├── data/
│ ├── sample-logs/
│ │ ├── auth-baseline.log ← Normal SSH activity (no attacks)
│ │ ├── auth-hydra-run.log ← Captured during Hydra trial
│ │ └── auth-msf-run.log ← Captured during Metasploit trial
│ │
│ ├── wordlists/
│ │ ├── common-usernames-50.txt
│ │ └── common-usernames-100.txt
│ │
│ └── results/ ← Auto-generated (gitignored)
│ ├── investigation-summary.json
│ ├── manual-enumeration-results.json
│ ├── timing-analysis.json
│ └── detection-report.json
│
├── tests/
│ ├── test_enumeration.py
│ ├── test_detection.py
│ └── test_log_parser.py
│
├── case-study/
│ └── User_Enumeration_attempt_using_manual_SSH.docx
│
└── screenshots/
├── manual-ssh-same-response.png
├── hydra-no-enumeration-support.png
├── metasploit-hardened-detected.png
├── auth-log-hydra-evidence.png
└── detection-alerts-output.png
```
## ⚡ 快速开始
```
# 1. Clone 并安装依赖
git clone https://github.com/Alisha-chaudhary/ssh-enum
cd ssh-enum
pip install -r requirements.txt
# 2. 仅运行 banner fingerprint(无需 credentials)
python -c "
from src.attack_tools.banner_fingerprinter import BannerFingerprinter
r = BannerFingerprinter().grab('192.168.xx.xxxx')
print(r.raw_banner, r.cves)
"
# 3. 运行完整的调查 pipeline
python run_investigation.py \
-target 192.168.xx.xxxx \
-usernames data/wordlists/common-usernames-50.txt \
-log data/sample-logs/auth-hydra-run.log \
-known-valid root ubuntu \
-samples 10
# 4. 仅分析 log file(无需实时 target)
python -c "
from src.detection_tools.pattern_detector import EnumerationDetector
d = EnumerationDetector('data/sample-logs/auth-hydra-run.log')
import json; print(json.dumps(d.run_all(), indent=2))
"
```
**要求:**
```
paramiko>=3.3.1
scipy>=1.11.0
Hydra and Metasploit must be installed separately (pre-installed on Kali Linux).
```
## 📚 参考
| 资源 | 相关性 |
|---------------------------------------------------------------------------------------|-------------------------------------------------|
| [CVE-2016-6210](https://nvd.nist.gov/vuln/detail/CVE-2016-6210) | 本项目测试的计时旁路侧信道 |
| [CVE-2024-6387 (regreSSHion)](https://nvd.nist.gov/vuln/detail/CVE-2024-6387) | OpenSSH ≤ 9.7 中的无需认证 RCE |
| [OpenSSH sshd_config 手册](https://man.openbsd.org/sshd_config) | `UsePAM`、`MaxAuthTries`、`VersionAddendum` |
| [OWASP — 用户枚举](https://owasp.org/www-community/attacks/User_Enumeration) | 一般的枚举攻击模式 |
| [RFC 4252 — SSH 身份验证协议](https://tools.ietf.org/html/rfc4252) | 协议规范;定义了错误消息行为 |
| [fail2ban 文档](https://www.fail2ban.org/wiki/index.php/Main_Page) | 速率限制和 IP 封禁 |
## 🎓 展现的技能
| 领域 | 证据 |
|------------------------|---------------------------------------------------------------------------------------------------------|
| SSH 协议内部机制 | 了解 `UsePAM` 计时归一化、CVE-2016-6210 修复、banner 信息暴露 |
| 进攻性安全 | 在结构化方法论中实际应用 Hydra、Metasploit 和自定义 Paramiko 探测 |
| 统计分析 | Welch's t-test、Cohen's d、应用于计时数据的变异系数 |
| 检测工程 | 跨四种模式类型的基于日志的 IOC 检测;结构化的警报输出 |
| Python 工程 | Dataclasses、类型提示、子进程自动化、正则解析、统计库 |
| 安全研究 | 假设 → 受控实验 → 证据收集 → 记录发现 → 可执行的结论 |
**状态:** 已完成 | **测试环境:** Ubuntu Server 22.04 LTS + OpenSSH 8.9p1 | Kali Linux 2024.1
标签:Maven, OpenSSH, 侧信道分析, 漏洞验证, 用户枚举, 统计分析, 逆向工具