对 OpenSSH 用户名枚举的可重现再调查,基于统计分析。
本项目重新调查了 CVE-2016-6210,一个已知的 OpenSSH 定时侧信道漏洞,旨在确定其在现代 Ubuntu Server 使用默认 PAM 配置时是否仍然可观测。
项目并未假设已公开的行为仍然适用,而是通过手动探测、Hydra 和 Metasploit 收集认证计时测量值,并运用 韦尔奇的 t 检验 和 科恩的 d 值 来区分真实的计时信号与测量噪声。
研究发现,在测试的默认配置下 没有统计上显著的计时差异,这证明了可重现实验与基于证据的安全声明验证的价值。
⚠️ 法律声明
本项目完全在自有的隔离实验室环境中进行。所有发现仅适用于所测试的配置。切勿测试不属于你或未经明确书面授权的系统。
用户名枚举 —— 即无需有效凭据即可判断远程系统上是否存在特定用户名的能力。它是攻击链中迈向账户沦陷的关键第一步:``` Reconnaissance → [User Enumeration] → Password Attack → Access ↑ This project investigates here
如果攻击者能够通过分析服务器响应区分“此用户存在”与“此用户不存在”,他们就能显著缩小后续暴力破解或凭证填充攻击的密钥空间。
SSH 是常见目标,因为它几乎普遍暴露在外、处理密码认证,且旧版本在有效与无效用户名之间存在可测量的时间差异(CVE-2016-6210)。
**本调查提出两个问题:**
1. 默认配置下的 Ubuntu 22.04.5 LTS 上的现代 OpenSSH 是否通过响应消息、时间或工具报告的信号泄露用户名存在性?
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 而引入的。
每种攻击方法均作为独立试验运行,且日志状态为干净状态:```bash
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 横幅
### 攻击方法
| 方法 | 工具 | 词表 | 目的 |
|-----------------------|--------------------------------------|-------------------------|-------------------------------------------------|
| 手动 SSH | `ssh` CLI + Paramiko | 50 个常见用户名 | 基线;检查原始响应 |
| Hydra 暴力破解 | `hydra` | 相同 50 个 | 自动化;利用 Hydra 内置的枚举模式 |
| Metasploit 模块 | `auxiliary/scanner/ssh/ssh_enumuser` | 相同 50 个 | 框架的专用枚举模块 |
| 横幅指纹识别 | 自定义 `BannerFingerprinter` | N/A | 无认证版本泄露,CVE 检查 |
| 定时分析 | 自定义 `ResponseAnalyzer` | 有效与无效子集 | 统计侧信道检查 |
---
## 构建了什么
本项目不仅仅运行工具——它将所有攻击和检测逻辑封装在一个结构化的 Python 代码库中,并提供了一个编排器,用于端到端运行整个流水线。
### 攻击工具 (`src/attack_tools/`)
**`ManualSSHEnumerator`** — 使用 `paramiko` 对每个用户名测试 N 次,记录精确的定时、结果类型和 SSH 横幅。计算每个用户名的均值/标准差。关键的是,它**不**在尝试之间重用连接,确保每个样本捕获完整的服务器端处理时间。
**`BannerFingerprinter`** — 通过原始 TCP 套接字抓取 SSH 横幅(无需凭证)。解析实现名称、版本字符串和操作系统提示。与本地 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`** — 对来自有效和无效用户名的定时分布执行韦尔奇 t 检验。计算定时差值(毫秒)、p 值、Cohen's d 效应量和通俗结论。阈值:delta ≥ 5ms 且 p < 0.05 触发侧信道警告。
**`EnumerationDetector`** — 四种检测模式:
- **快速用户名探测**:滑动窗口 - 同一 IP,60 秒内 ≥10 个不同用户名
- **词表关联**:尝试的用户名与已知攻击列表之间的匹配率
- **顺序定时**:尝试间隔的变异系数(低 CoV 表示工具)
- **分布式探测**:来自多个 IP 的相同用户名(凭证填充侦察)
**`AlertingSystem`** — 轻量级告警发射器。生成带时间戳的 JSON 告警到 stdout。可根据需要扩展电子邮件/SIEM/Webhook 集成。
### 编排器
**`run_investigation.py`** — CLI 驱动程序,按顺序运行所有四个阶段并将结果写入 `data/results/`。使用 `--help` 获取完整用法。```bash
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
Hypothesis tested: Does OpenSSH return a different error message for a non-existent user than for an existing user with a wrong password?```bash
$ ssh [email protected] Permission denied (publickey,password).
$ ssh [email protected] Permission denied (publickey,password).
**Result:** 响应字节级完全一致。该协议未泄露任何信息。
**Why:** 自 OpenSSH 7.3 起,`UsePAM yes` 会强制服务器对不存在的用户执行一次傀儡 `crypt()` 操作,从而在时间上和错误路径上与真实认证失败保持一致。此修复是直接针对 CVE-2016-6210 的回应。
---
### 发现 2:未检测到计时侧信道
**测试假设:** 即使错误消息匹配,是否存在可被统计利用的可测量的有效用户名与无效用户名之间的计时差异?
对 50 个用户名分别采集了 10 个计时样本。将系统确认的已知有效用户与无效用户池进行比较。
| 指标 | 值 |
|---------------------------|-------------------------------------|
| 无效用户平均计时 | ~312 ms |
| 有效用户平均计时 | ~311 ms |
| 差异 | **~1 ms** |
| Welch t 检验 p 值 | > 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、时间戳和尝试的用户名。攻击者的存在完全可见。
auxiliary/scanner/ssh/ssh_enumuser 模块在尝试枚举前会从横幅中检查 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)
### 发现5:即使枚举失败,检测也是可靠的
从防御者的角度来看,关键见解是:**攻击即使未成功也会产生噪音**。所有四种检测模式都正确触发了对收集到的auth.log的分析:
| 检测 | 触发条件 | 严重程度 |
|----------------------|-----------------------------------------------|----------|
| 快速用户探测 | Kali IP在60秒内探测了50个用户名 | 高 |
| 词库关联 | 48/50个尝试的用户名匹配词库 | 高 |
| 时序分析 | 尝试间变异系数=0.04(工具签名) | 中 |
| 仅横幅探测 | 在发送任何用户名之前进行预认证断开 | 低 |
---
## 思考过程
### 为什么首先进行手动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`引入受控延迟和抖动),以查看结论在现实条件下的表现。
---
## 安全风险
尽管在此实验环境中枚举未成功,但攻击面和相关风险如下: