
統計分析を用いた OpenSSH ユーザ名列挙の再現可能な再調査
このプロジェクトは、文書化された OpenSSH のタイミングサイドチャネルである CVE-2016-6210 を再調査し、デフォルトの PAM 設定を使用した最新の Ubuntu Server で依然として観測可能かどうかを判断します。
公開された動作が依然として適用可能であると仮定するのではなく、このプロジェクトは、手動プロービング、Hydra、Metasploit を通じて収集された認証タイミング測定値を、Welch の t 検定 と Cohen の d を使用して評価し、真のタイミング信号を測定ノイズから区別します。
この調査では、テストしたデフォルト設定において 統計的に有意なタイミング差は見られず、再現可能な実験と証拠に基づく公開セキュリティ主張の検証の重要性を示しています。
⚠️ 法的注意事項
このプロジェクトは、完全に自己所有の隔離された実験環境内で実施されました。すべての調査結果はテストされた設定にのみ適用されます。所有していない、または明示的な書面による許可を得ていないシステムをテストしないでください。
ユーザ名列挙 - 有効な資格情報なしで特定のユーザ名がリモートシステムに存在するかどうかを判断する能力。アカウント侵害につながる攻撃チェーンの重要な最初のステップです:``` Reconnaissance → [User Enumeration] → Password Attack → Access ↑ This project investigates here
If an attacker can distinguish "this user exists" from "this user does not exist" by analysing server responses, they can dramatically reduce the keyspace for subsequent
brute force or credential stuffing attacks.
SSH is a frequent target because it is nearly universally exposed, handles password authentication, and older implementations had measurable timing differences between valid and invalid usernames (CVE-2016-6210).
**This investigation asks two questions:**
1. Does modern OpenSSH on Ubuntu 22.04.5 LTS with default configuration leak username existence
via response messages, timing, or tool-reported signals?
2. If an attacker makes the attempt regardless, what artefacts does it leave? and how
reliably can those be detected?
---
## 🖥️ Lab Setup
All testing was performed in a fully isolated host-only virtual network with no internet
exposure.
| Machine | OS | Role | IP | SSH Version |
|----------|---------------------------|-----------------------------------------|------------------|------------------|
| Attacker | Kali Linux 2024.1 | Offensive tools, analysis scripts | 192.168.56.5 | — |
| Target | Ubuntu Server 22.04.5 LTS | Running OpenSSH with **default** config | 192.168.56.10 | OpenSSH 8.9p1 |
**Target SSH configuration (`/etc/ssh/sshd_config` defaults):**```
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` | 有効 vs 無効のサブセット | 統計的サイドチャネルチェック |
---
## 構築したもの
このプロジェクトは単にツールを実行するだけではありません。各攻撃とすべての検出ロジックを構造化されたPythonコードベースでラップし、パイプライン全体をエンドツーエンドで実行するオーケストレーターを提供します。
### 攻撃ツール(`src/attack_tools/`)
**`ManualSSHEnumerator`** — `paramiko`を使用して各ユーザー名をN回テストし、正確なタイミング、結果の種類、SSHバナーを記録します。ユーザー名ごとに平均/標準偏差を計算します。重要なのは、試行間で接続を再利用**しない**ことで、各サンプルがサーバー側の処理時間全体を捕捉することを保証します。
**`BannerFingerprinter`** — 生のTCPソケットを介してSSHバナーを取得します(認証情報は不要)。実装名、バージョン文字列、OSヒントを解析します。ローカルのCVEレジストリとクロスリファレンスします。`OpenSSH_8.9p1 Ubuntu-3ubuntu0.6` のようなバージョンは、正確なサーバーソフトウェアを明らかにします — 認証が試行される前に既知の脆弱性を特定するのに十分な場合もあります。
**`HydraAutomation`** — Hydraをラップするサブプロセスラッパー。stdoutを解析して、成功したログイン、エラーメッセージ、Hydra自身の列挙判定(`does not support user enumeration`)を抽出します。
**`MetasploitScanner`** — 一時的なリソーススクリプトを作成し、サブプロセスを介して `msfconsole` を駆動します。出力を解析して、ハードニング検出と見つかったユーザー名を取得します。
### 検出ツール(`src/detection_tools/`)
**`LogParser`** — 正規表現ベースのauth.logパーサー。5つのSSHイベントタイプをサポートします: `failed_invalid_user`, `failed_valid_user`, `pre_auth_reject`, `accepted`, `disconnected`。タイムスタンプ、イベントタイプ、ユーザー名、送信元IP、ポートを含む構造化されたイベント辞書を返します。
**`ResponseAnalyzer`** — 有効なユーザー名と無効なユーザー名からのタイミング分布に対してウェルチのt検定を実行します。タイミングデルタ(ms)、p値、コーエンのd効果量、平易な結論を計算します。しきい値: デルタ ≥ 5ms かつ p < 0.05 でサイドチャネル警告をトリガーします。
**`EnumerationDetector`** — 4つの検出パターン:
- **迅速なユーザープローブ**: スライディングウィンドウ - 同じIP、60秒以内に10以上の異なるユーザー名
- **ワードリスト相関**: 試行されたユーザー名と既知の攻撃リストとの一致率
- **シーケンシャルタイミング**: 試行間隔の変動係数(低CoV → ツール)
- **分散プロービング**: 複数のIPからの同一ユーザー名(クレデンシャルスタッフィングの偵察)
**`AlertingSystem`** — 軽量アラートエミッター。タイムスタンプ付きのJSONアラートをstdoutに生成します。必要に応じてメール/SIEM/ウェブフック統合で拡張可能です。
### オーケストレーター
**`run_investigation.py`** — 4つの全ステージを順次実行し、結果を `data/results/` に書き込むCLIドライバー。完全な使用法については `--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
検証した仮説: OpenSSHは存在しないユーザーに対して、存在するユーザーが間違ったパスワードを入力した場合とは異なるエラーメッセージを返すのか?```bash
$ ssh [email protected] Permission denied (publickey,password).
$ ssh [email protected] Permission denied (publickey,password).
**結果:** レスポンスはバイト単位で同一です。プロトコルは何も漏洩しません。
**理由:** OpenSSH 7.3以降、`UsePAM yes`により、存在しないユーザーに対してサーバーはダミーの`crypt()`操作を実行するよう強制されます。これにより、実際の認証失敗のタイミングとエラーパスの両方が一致します。この修正はCVE-2016-6210への直接的な対応でした。
---
### 発見2: タイミングサイドチャネルは検出されず
**検証した仮説:** エラーメッセージが一致していても、有効なユーザー名と無効なユーザー名の間で統計的に悪用可能なタイミングの差が測定できるか?
50のユーザー名それぞれについて10のタイミングサンプルを収集しました。システムから確認された既知の有効ユーザーを無効ユーザープールと比較しました。
| 指標 | 値 |
|-----------------------------|-------------------------------------|
| 平均タイミング — 無効ユーザー | ~312 ms |
| 平均タイミング — 有効ユーザー | ~311 ms |
| 差分 | **~1 ms** |
| ウェルチのt検定p値 | > 0.40 |
| 結論 | **識別可能なサイドチャネルなし** |
約1msの差分は5msのノイズしきい値をはるかに下回り、統計的に有意ではありません(p >> 0.05)。OpenSSHのダミーハッシュ計算は効果的です。
---
### 発見3: Hydraが列挙サポートなしと報告
HydraのSSH列挙モードは、異なるエラーメッセージ、異なるタイミング、または異なる接続動作の3つのシグナルのいずれかに依存しています。これら3つすべてが平準化されているため、Hydraは明示的に次のように報告します:```
[ERROR] target ssh://192.168.56.10:22/ does not support user enumeration
[STATUS] 50/50 tries completed, 0 valid logins found
Side effect observed: Despite failing to enumerate, all 50 attempts are logged in
/var/log/auth.log with source IP, timestamp, and attempted username. The attacker's
presence is fully visible.
The auxiliary/scanner/ssh/ssh_enumuser module checks the OpenSSH version from the
banner before attempting enumeration. Versions ≥ 7.3 with UsePAM yes are flagged as
hardened and the module exits early:```
[] 192.168.xx.xxxx:22 - SSH - Checking for vulnerability
[] 192.168.xx.xxxx:22 - SSH - Target is not vulnerable: OpenSSH 8.9p1 (hardened)
これは有用な発見である。バナーだけで、攻撃者は列挙試行を行う前にサーバーの防御姿勢を把握できる。
---
### 発見5: 列挙が失敗しても検知は確実である