
This project explores whether modern OpenSSH reveals valid usernames through subtle response or timing differences. CVE-2016-6210 user enumeration investigation ( Welch's t-test, Cohen's d, and detection engineering ) on a controlled lab on Ubuntu 22.04.5 LTS, it also examines the traces such attempts leave behind and how they can be detected..
統計分析を用いた 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: 列挙が失敗しても検知は確実である
防御側の観点から見た重要な洞察は、**攻撃が成功しなくてもノイズを発生させる** という点である。収集したauth.logに対して、4つの検知パターンすべてが正しく発動した。
| 検知 | トリガー | 重要度 |
|------------------------|----------------------------------------------------------|----------|
| 迅速なユーザープローブ | Kali IPが<60秒で50のユーザー名をプローブ | HIGH |
| ワードリスト相関 | 試行された名前の48/50がワードリストと一致 | HIGH |
| 逐次タイミング | 試行間の変動係数 = 0.04(ツールのシグネチャ) | MEDIUM |
| バナーのみプローブ | ユーザー名が送信される前の認証前切断 | LOW |
---
## 思考プロセス
### なぜ最初に手動SSH列挙を行うのか?
手動テストから始めるという直感は方法論として正しかった。ツールの出力を信頼する前に、生のプロトコルが実際に何を言っているのかを理解する必要がある。`ssh ghost@target` を実行し、正確なエラーメッセージを観察することで、自動化に時間を投資する前に列挙すべきものが *あるかどうか* がわかる。
最初の観察、つまり `Permission denied (publickey,password)` はユーザーが存在するかどうかに関係なく同じに見える、という点が中心的な発見であった。以降のすべてはその結果の検証である。
### 立てられた(そして再検討された)前提
最初の前提は、Hydra と Metasploit は手動テストよりも *優れている* ため、手動が失敗してもツールなら成功するかもしれない、というものだった。これは予想された方向では間違っていたが、*理由* は正しかった。ツールはここでは能力を追加しない。なぜならプロトコル自体がシグナルを漏洩しないからである。ツールは同じプロトコルを自動化したものに過ぎない。
もう一つ検討に値する前提:最初の手動試行は後続の試行よりも明らかに遅く、パスワード成功の試行は速かった。これは当初、潜在的なタイミングシグナルとして解釈された。よく考えると、この遅延はTCP接続確立のオーバーヘッド(ARP解決、接続設定)によるものであり、サーバー側の処理時間ではない。これを制御するには、TCPハンドシェイク *後* の `time.perf_counter()` から測定するか、最初のサンプルを破棄する方がより厳密だった。`ManualSSHEnumerator` の実装は、ユーザー名あたり10サンプルを収集し平均と標準偏差を報告することでこの問題に対処しており、最初のサンプルのノイズを希釈している。
### プロジェクト中に変わったこと
元々の範囲は狭く、3つのツールを実行し、それらが機能するかどうかを文書化するだけだった。プロジェクトは2つの方向に進化した。
**内側(より深い分析):** 最初の結果が否定的だったとき、自然と *なぜ* という疑問が湧き、OpenSSHの変更履歴、CVE-2016-6210、`UsePAM` の実装を読むことになった。メカニズムを理解することは、結果を記録するだけよりも価値がある。
**外側(検知への転換):** 否定的な攻撃結果も防御側にとって有用なデータポイントである。「列挙は失敗したが、サーバーは何を見たのか?」という転換により、ログ分析と検知エンジニアリングの要素が加わり、単一次元のツール実行演習が双方向の調査に変わった。
### 異なる方法で行うであろうこと
タイミング測定はホストオンリーの仮想ネットワーク上で行われた。これは実際のネットワークよりもジッタが少ないが、結果が楽観的であることも意味する。TCPレイテンシ、ジッタ、再送がある実際の環境では、ノイズフロアが高くなり、タイミング分析にはユーザー名あたりにより多くのサンプルが必要になる。より堅牢な方法論は、シミュレートされたWANリンク(`tc netem` を使用して制御されたレイテンシとジッタを導入)を介してテストし、現実的な条件下で結論がどのように成り立つかを確認することである。
---
## セキュリティリスク
このラボでは列挙は成功しなかったが、攻撃対象領域と関連するリスクは以下の通りである。
**列挙が *可能だった* 場合(例:古いOpenSSH、`UsePAM no`、カスタムPAMスタック):**
- 攻撃者はブルートフォースキャンペーンを確認済みの有効なユーザー名のみに絞り込み、検知リスクを低減し効率を劇的に向上させることができる。
- パスワードスプレー(すべての有効なユーザー名に対して1つの共通パスワード)と組み合わせることで、ユーザーごとの `MaxAuthTries` ロックアウトを回避できる。
**列挙耐性があっても適用されるリスク:**
- SSHバナーは正確なOpenSSHバージョンとOSを漏洩させる。`OpenSSH_8.9p1` を見た攻撃者は、単一の認証パケットを送信する前に、CVE-2024-6387(regreSSHion)が該当するかどうかを即座に確認できる。
- すべての列挙試行は送信元IPと共にログに記録される。ログ監視がない場合、スローバーン攻撃(1時間に1回の試行)はレートベースのアラートをトリガーせずに数千のユーザー名をプローブする可能性がある。
- `PasswordAuthentication yes` は、列挙が実行可能でなくても、パスワードベースの攻撃対象領域を開いたままにする。OSINT後の資格情報攻撃(流出したパスワードリストをOSINTで得たユーザー名に対して使用する)は、サーバー側の列挙をまったく必要としない。
---
## 緩和戦略
| 脅威 | 緩和策 | 必要な設定変更 |
|-------------------------------|----------------------------------------------------------------|----------------------------------------------|
| タイミングサイドチャネル | `UsePAM yes` を確実にする(Ubuntuのデフォルト) | なし — 既にデフォルト |
| バナーバージョン開示 | `sshd_config` で `VersionAddendum none` と `DebianBanner no` | はい |
| パスワードベース攻撃 | `PasswordAuthentication no` — キーのみの認証 | はい |
| OSINT後のブルートフォース | `sshd` 牢獄を使用した `fail2ban` | インストール+設定 |
| スローバーン列挙 | SIEMへのログ転送;IP/時間あたりNを超える異なるユーザー名で警告 | SIEMが必要 |
| ルートログイン | `PermitRootLogin no` | はい(デフォルトは `prohibit-password`) |
| 認証前切断 | `MaxStartups 10:30:60` で未認証接続をレート制限 | はい |
**強化されたデプロイメントのための最小推奨 `sshd_config` 追加項目:**```
PasswordAuthentication no
PermitRootLogin no
MaxAuthTries 3
MaxStartups 10:30:60
VersionAddendum none
LogLevel VERBOSE
現在のプロジェクトは、1つのプロトコルを1つの構成でテストします。自然な拡張として以下が考えられます:
同一ホスト上の他のサービスの列挙。 SMTP(VRFY/EXPN)、LDAP(属性クエリ)、HTTPログインフォーム、SNMPはすべて、SSHで強化された同一マシン上の一般的なユーザー名漏洩ベクトルです。サービス間の比較研究により、より完全なリスク像が得られるでしょう。
非デフォルトのSSH構成のテスト。 UsePAM no、カスタムPAMモジュール、Kerberos認証バックエンド、および古いOpenSSHバージョン(組み込みシステムやネットワークアプライアンスに導入されている)は、依然としてタイミング漏洩を示す可能性があります。同じパイプラインを意図的に脆弱な構成に対してテストすることで、その対比が明らかになるでしょう。
inotifyを使用したライブ検出。 現在の検出は、コピーされたログファイルに対して事後的に実行されます。本番グレードのバージョンでは、inotify(またはtail -f + パーサースレッド)を使用して、列挙試行が開始されてから数秒以内にほぼリアルタイムで検出および警告を行います。
ネットワークレベルの検出。 Auth.logはホストベースのアーティファクトです。パケットレベルの検出で補完します:認証ハンドシェイクを完了する前に閉じるポート22への短命なTCP接続は、バナーのみのフィンガープリンティングの兆候です。これはZeekまたはSuricataルールとして実装できます。
統計レポートのためのJupyterノートブック。 収集されたタイミングデータは可視化に適しています - ユーザー名ごとのタイミング分布の箱ひげ図、経時的な試行頻度の散布図、送信元IPのヒートマップ。ノートブックにより、分析が再現可能で共有可能になります。
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
## ⚡ クイックスタート```bash
# 1. Clone and install dependencies
git clone https://github.com/Alisha-chaudhary/ssh-enum
cd ssh-enum
pip install -r requirements.txt
# 2. Run just the banner fingerprint (no credentials needed)
python -c "
from src.attack_tools.banner_fingerprinter import BannerFingerprinter
r = BannerFingerprinter().grab('192.168.xx.xxxx')
print(r.raw_banner, r.cves)
"
# 3. Run the full investigation 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. Analyse a log file only (no live target needed)
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 manual](https://man.openbsd.org/sshd_config) | `UsePAM`、`MaxAuthTries`、`VersionAddendum` の各パラメータ |
| [OWASP — User Enumeration](https://owasp.org/www-community/attacks/User_Enumeration) | 一般的な列挙攻撃パターン |
| [RFC 4252 — SSH Authentication Protocol](https://tools.ietf.org/html/rfc4252) | プロトコル仕様。エラーメッセージの動作を定義 |
| [fail2ban documentation](https://www.fail2ban.org/wiki/index.php/Main_Page) | レート制限とIP禁止 |
---
## 🎓 示されたスキル
| ドメイン | 証拠 |
|--------------------------|-----------------------------------------------------------------------------------------------------|
| SSHプロトコル内部 | `UsePAM`タイミング正規化、CVE-2016-6210修正、バナー情報漏洩の理解 |
| オフェンシブセキュリティ | Hydra、Metasploit、カスタムParamikoプロービングの体系的な方法論における実践的使用 |
| 統計分析 | タイミングデータに適用されたウェルチのt検定、コーエンのd、変動係数 |
| 検出エンジニアリング | 4つのパターンタイプにわたるログベースのIOC検出。構造化されたアラート出力 |
| Pythonエンジニアリング | データクラス、型ヒント、サブプロセス自動化、正規表現解析、統計ライブラリ |
| セキュリティ研究 | 仮説 → 制御実験 → 証拠収集 → 文書化された発見 → 実用的な結論 |
---
**ステータス:** 完了 | **テスト環境:** Ubuntu Server 22.04 LTS + OpenSSH 8.9p1 | Kali Linux 2024.1