社内ネットワーク侵入後の「管理者権限奪取(Kerberoasting / Pass-the-Hash)」はどう起きるか?
最小権限とセグメント分離の鉄則
対象:経営者様・社内システム管理者様・Windowsサーバーや共有NASを運用中のご担当者様 / 読了目安:約6分
この記事の要点と4つの章のご案内
| 章構成 | 主なテーマ | 要点と確認ポイント |
|---|---|---|
| 1. 基本と全体像 | 身近なたとえで見る仕組み:なぜ「1つの客室」に入った泥棒が「ホテル全室の金庫」を開けられるのか? | ランサムウェア被害で全社の業務が止まる最大の原因は、最初の1台の感染ではなく、その後に社内ネットワークを伝って「全体のマスターキー(ドメイン管理者権限)」が奪われることにあります。 |
| 2. 現場での進め方と対策 | 構造図解:「全社一斉感染するフラットな社内網」と「被害を1台で止める防火壁ネットワーク」 | 攻撃者は「Pass-the-Hash(メモリ上の合言葉データの使い回し)」や「Kerberoasting(古い暗号方式のチケット解読)」を使い、パスワードそのものを知らなくても数十分で最高権限へ昇格します。 |
| 3. 関連する制度とルール | 現場で陥りやすい落とし穴と回避策 | 被害を最初の1台だけで封じ込めるには、「普段の業務に管理者アカウントを使わない(最小権限)」「パソコン同士の直接通信を遮断し部門ごとに部屋を分ける(セグメント分離)」の2点が決定打となります。 |
| 4. 詳しい技術仕様としくみ | 理解を深める確認クイズ | ニュースで「ランサムウェア被害により社内のサーバー数十台がすべて暗号化され、業務が全面停止」という報道を目にしたとき、「どうして1台のパソコンがメールの添付ファイルを開いただけで、会社中のすべてのパソコンやサーバーまで一瞬で感染してしまうのだろう?」と疑問に思われたことはないでしょうか。 |
- 01. ランサムウェア被害で全社の業務が止まる最大の原因は、最初の1台の感染ではなく、その後に社内ネットワークを伝って「全体のマスターキー(ドメイン管理者権限)」が奪われることにあります。
- 02. 攻撃者は「Pass-the-Hash(メモリ上の合言葉データの使い回し)」や「Kerberoasting(古い暗号方式のチケット解読)」を使い、パスワードそのものを知らなくても数十分で最高権限へ昇格します。
- 03. 被害を最初の1台だけで封じ込めるには、「普段の業務に管理者アカウントを使わない(最小権限)」「パソコン同士の直接通信を遮断し部門ごとに部屋を分ける(セグメント分離)」の2点が決定打となります。
01. 身近なたとえで見る仕組み:なぜ「1つの客室」に入った泥棒が「ホテル全室の金庫」を開けられるのか?
ニュースで「ランサムウェア被害により社内のサーバー数十台がすべて暗号化され、業務が全面停止」という報道を目にしたとき、「どうして1台のパソコンがメールの添付ファイルを開いただけで、会社中のすべてのパソコンやサーバーまで一瞬で感染してしまうのだろう?」と疑問に思われたことはないでしょうか。
その秘密は、多くの企業や病院で使われている「一括管理の仕組み(Active Directoryや共通の管理者設定)」が、便利さと引き換えに抱えている弱点にあります。
これを「100室あるホテル」にたとえてみましょう。もしホテルの支配人が、「鍵を持ち歩くのが面倒だから」という理由で、すべての客室のテーブルの上に『ホテル全室を開けられるマスターキー』を置いていたらどうなるでしょうか。泥棒はまず一番入りやすい1階の客室(一般社員のパソコン)に1つ忍び込むだけで、そこにあるマスターキーを拾い、エレベーターで最上階の金庫室(基幹サーバーやバックアップ)まで堂々と入ってすべてをロックしてしまいます。
手口 01:Pass-the-Hash(パス・ザ・ハッシュ=合言葉スタンプの丸ごとコピー)
パソコンのメモリ(一時記憶領域)の中には、ログインした人の「暗号化された合言葉(ハッシュ値)」が残っています。もし全パソコンの管理者パスワードを同じにしていたり、システム管理者が一般パソコンに管理者IDでログインしたりすると、攻撃者は元のパスワード文字列を解読することなく、メモリ上の「合言葉スタンプ」をそのままコピーして隣のパソコンやサーバーへ次々と乗り移ります。
手口 02:Kerberoasting(ケルベロースティング=通行証チケットの持ち帰り解読)
社内サーバー(Active Directory)では、一般社員でも「社内システムを使うための通行証チケット」をサーバーに請求できます。この通行証が古い暗号方式(RC4)で発行されていると、攻撃者は通行証データを自分のパソコンに持ち帰り、高性能な画像処理ボード(GPU)を使って1秒間に数百億回の総当たり計算を行い、数時間のうちにサーバー管理者のパスワードを割り出してしまいます。
初期侵入から社内ネットワークを横展開(ラテラルムーブメント)し、ドメイン管理者権限を奪取するまでの時間は年々短縮されており、夜間や休日の数時間で完了します。
古いRC4-HMAC方式のサービスチケットは、市販GPUクラスタを用いたオフライン解析により、8〜10文字程度の単純なパスワードなら数分〜数時間で解読されます。
ローカル管理者パスワードの個別化(LAPS)とVLANによるネットワーク分割を実施していた組織では、万一の感染時も被害を単一端末・単一区画に封じ込められます。
02. 構造図解:「全社一斉感染するフラットな社内網」と「被害を1台で止める防火壁ネットワーク」
社内のすべてのパソコンとサーバーが「同じ1つの大きな部屋(フラットなネットワーク)」に繋がっており、しかも共通の管理者パスワードが使われている状態と、部屋ごとに防火扉(セグメント分離)を設けた状態を比較してみましょう。
03. 現場で陥りやすい落とし穴と回避策
中小企業や病院・工場の社内ネットワークを点検すると、長年の運用の積み重ねから「泥棒にとって一番動きやすい設定」がそのまま残っていることが少なくありません。特に注意すべき3つの落とし穴と、今日からできる改善手順を見ていきましょう。
現場の実態:「社内のパソコン50台すべてに、同じローカルAdministratorパスワードを設定して配っている」
回避策: パソコンを導入する際に「セットアップが楽だから」と全端末で同じ管理者パスワードを設定していると、1台が感染した瞬間にPass-the-Hash攻撃で残り49台すべてに数秒で侵入されます。Windows標準の無料機能である「Windows LAPS(ローカル管理者パスワードソリューション)」を有効にし、パソコン1台ごとに異なるランダムな管理者パスワードが自動設定・定期変更されるようにしましょう。
現場の実態:「システム担当者が、一般社員のパソコンを直すときに『ドメイン管理者(Domain Admins)』のIDとパスワードを入力してログインしている」
回避策: 最高権限を持つ「Domain Admins」で一般のパソコンに一度でもログインすると、そのパソコンのメモリ内に最高権限の認証情報が残ります。もしそのパソコンにウイルスが潜んでいれば、その瞬間に全社のマスターキーが奪われます。「サーバー管理用の特権ID」と「普段メールを見たりパソコンを修理したりするID」は必ず別々に分け、最高権限IDは管理対象サーバー以外では原則として使わないルール(階層化管理)を一貫してください。
現場の実態:「便利だからと、バックアップ用のNASもActive Directoryに参加させ、ドメイン管理者なら誰でも消せる設定にしている」
回避策: 攻撃者がドメイン管理者権限を奪った後に最初に行うのは、「バックアップサーバーを探し出して初期化・削除すること」です。バックアップ保管庫は必ず社内ドメイン(Active Directory)から構造的に切り離し(ワークグループ分離・別VLAN)、万が一ドメイン管理者が乗っ取られても削除できない「書き換え不能(イミュータブル)スナップショット」で保護してください。
社内ネットワークの「横展開・権限奪取」を防ぐ3項目チェックリスト
自社のパソコン・サーバー環境に当てはまるか、3つの基本項目をクリックして点検してみましょう。
04. 理解を深める確認クイズ
質問:社内のパソコン30台を管理する際、「1台がウイルス感染しても他のパソコンやサーバーへ被害を広げない(横展開を防ぐ)」ために最も効果的な設定はどれでしょうか?
選択肢 A:管理しやすいように、30台すべての管理者パスワードを同じにしておく 解説を見る ↓
これは最も避けるべき危険な設定です。
1台のパソコンから管理者パスワードのハッシュ値が抜き取られると、「Pass-the-Hash」という手口で残り29台すべてに数秒で侵入されてしまいます。
選択肢 B:日常業務は「標準ユーザー権限」で行い、端末ごとの管理者パスワードを個別化(LAPS)した上でパソコン同士の直接通信を遮断する 解説を見る ↓
正解です。これが「最小権限」と「セグメント分離」の基本原則です。
万が一1台のパソコンで不審なファイルを開いてしまっても、管理者権限がなければシステム深部への侵入を防げ、さらに隣のパソコンへの通信が閉じていれば被害はその1台だけで止まります。
選択肢 C:システム管理者が全社員のパソコンに「Domain Admins(最高権限)」でリモートログインして設定作業を行う 解説を見る ↓
最高権限アカウントを一般端末で使うのは大変危険です。
一般端末のメモリ上に最高権限の認証情報が残ってしまい、そこからドメイン全体が乗っ取られる原因になります。
大型船が沈まないための知恵「水密隔壁(すいみつかくへき)」とネットワーク分離
現代の大型船舶は、船底が岩や氷山にぶつかって穴が開いても船全体が沈まないよう、船内をいくつもの独立した部屋に仕切る「水密隔壁」を備えています。仮に1つの区画に海水が流れ込んでも、隣の区画への扉を閉ざすことで浮力を保ち、乗客全員の命を守ります。社内ネットワークの「セグメント分離(VLAN分離)」や「最小権限の原則」もまったく同じ思想です。「原則として1滴も水が入らない船」を作ることは難しくても、「1区画に水が入っても原則として沈まない船」を作ることは、事前の設計ひとつで確実に実現できるのです。
社内ネットワークの権限整理・VLAN分離を点検してみませんか?
Active Directory権限診断・バックアップ隔離設計の個別相談・設定確認
なぜ「事務用パソコン1台の感染」で生産ラインや電子カルテ、全社のファイルサーバーまで同時に止まってしまうのか、ホテルのマスターキーのたとえ話で基本構造として整理しています。
「ソフトを入れるのが楽だから」と全員のパソコンを管理者(Administrator)のままにしていませんか?今日からできるアカウント整理とVLAN分離の手順を「第2章」で紹介します。
Kerberos TGS-REP(RC4-HMAC etype 23 vs AES256 etype 18)のオフライン解析数理、NTLMリレー、Tier 0〜2分離設計、およびRustによる横展開検知エンジンを「第3章」で詳解します。
Kerberos TGS-REP(RC4-HMAC vs AES256-CTS-HMAC-SHA1-96)のオフライン鍵空間解析、NTLMリレー詳細解説、およびRust 2024による横展開(Lateral Movement)異常検知器
本モノグラフでは、Active Directory環境における代表的な特権昇格手法である Kerberoasting(RFC 4757 `etype 23` ダウングレード要求)と Pass-the-Hash / NTLM Relay の暗号学的脆弱性を分解する。その上で、`AES256-CTS-HMAC-SHA1-96`(RFC 3962 `etype 18`)+ Group Managed Service Accounts(gMSA 120文字ランダム鍵)によるオフライン解読の計算量的無効化、Tier 0/1/2 隔離モデル、および認証イベントグラフから横展開をリアルタイム検知する Rust 2024 実装を提示する。
1. Kerberos TGS-REQ / TGS-REP における RC4-HMAC (etype 23) の構造的欠陥:
Active Directory ドメイン内の任意の認証済みユーザー(一般権限)は、Service Principal Name(SPN)が登録されたサービスアカウントに対して KDC へ `TGS-REQ`(RFC 4120)を送信し、サービスの秘密鍵 K_service で暗号化されたチケットを含む `TGS-REP` を取得できる。もし `msDS-SupportedEncryptionTypes` で `RC4-HMAC-MD5`(RFC 4757, `etype = 0x17`)が許可されている場合、その鍵導出関数はソルトも反復ストレッチングも伴わない単発の MD4 ハッシュ(すなわち NTLM ハッシュそのもの)である:
K_RC4 = MD4(UTF-16LE(P))
攻撃者はネットワーク越しにロックアウトを一切発生させることなく、抽出した `TGS-REP` 暗号文に対してオフラインで毎秒 R_RC4 ≈ 3.5 × 10^10 guesses/s の高速辞書・ブルートフォース攻撃を実行できる。
2. AES256-CTS-HMAC-SHA1-96 (etype 18) + gMSA による計算量的封印:
一方、`RC4-HMAC` をドメインポリシーで確実な防止し、`AES256-CTS-HMAC-SHA1-96`(RFC 3962, `etype = 0x12`)を強制した場合、鍵導出にはレルム名とプリンシパル名を結合したソルト S と、反復回数 c = 4096 の PBKDF2-HMAC-SHA1 が適用される:
K_AES256 = DK(PBKDF2-HMAC-SHA1(P, S, 4096, 32), "kerberos")
これにより単一試行あたりの計算コストが約 10^4 倍に増大するだけでなく、サービスアカウントを人間が管理する固定パスワードから gMSA(Group Managed Service Account:120文字=960 bit の暗号学的乱数鍵を30日ごとに自動ローテーション)へ移行することで、探索空間は 2^960 となりオフライン解読確率は数学的に 0 へ収束する。
3. Pass-the-Hash と Tier 0/1/2 境界隔離モデル:
NTLM 認証および Kerberos Pre-Authentication はパスワード平文 P ではなく導出鍵 K を直接入力とするため、LSASS メモリから K が漏洩すると鍵自体が等価なクレデンシャルとして機能する(Pass-the-Hash / Overpass-the-Hash)。これを根絶するには、(a) `Protected Users` セキュリティグループへの特権ID所属(NTLM禁止・TGT寿命4時間制限・委任禁止)、(b) Tier 0(AD DC / PKI)、Tier 1(業務サーバー)、Tier 2(一般クライアントPC)間の双方向ログオン拒否GPO、および (c) SMB Signing / LDAP Channel Binding の強制が不可欠である。
| Attack Technique | Windows Security Event Indicator | Protocol Root Cause | Deterministic Remediation |
|---|---|---|---|
| Kerberoasting (T1558.003) | Event 4769 (`TicketEncryptionType == 0x17`, `TicketOptions == 0x40810000`) | Legacy RC4-HMAC allowed on SPN account | Enforce AES256 (`0x12`) only + Migrate to gMSA |
| AS-REP Roasting (T1558.004) | Event 4768 (`PreAuthType == 0`) | `DONT_REQ_PREAUTH` flag enabled on user | Audit & clear `UF_DONT_REQUIRE_PREAUTH` bit |
| Pass-the-Hash (T1550.002) | Event 4624 (`LogonType == 3`, `AuthPackage == NTLM`, `KeyLength == 0`) | Shared local Admin hash & NTLM enabled | Windows LAPS + Disable NTLM + Protected Users |
| NTLM Relay to LDAP/SMB (T1557.001) | Event 2889 (Unsigned LDAP bind) / SMBv2 unsigned session | Missing cryptographic session signing | Require SMB Signing + LDAP Signing & Channel Binding |
#![forbid(unsafe_code)]
use std::collections::{HashMap, HashSet};
/// Kerberos Encryption Types per RFC 3961 / RFC 4757 / RFC 3962.
pub const ETYPE_RC4_HMAC: u16 = 0x0017;
pub const ETYPE_AES128_CTS_HMAC_SHA1_96: u16 = 0x0011;
pub const ETYPE_AES256_CTS_HMAC_SHA1_96: u16 = 0x0012;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AdminTier {
Tier0DomainControl,
Tier1ServerFleet,
Tier2Workstation,
}
#[derive(Debug, Clone)]
pub struct AuthTelemetryEvent {
pub timestamp_sec: u64,
pub source_ip: u32,
pub target_host_id: u32,
pub account_sid_rid: u32,
pub account_tier: AdminTier,
pub target_tier: AdminTier,
pub event_id: u16, // 4769 (TGS-REQ) or 4624 (Logon)
pub kerberos_etype: u16, // Valid when event_id == 4769
pub is_ntlm_network_logon: bool,
pub spn_requested: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ThreatSignal {
KerberoastingRc4Downgrade { source_ip: u32, spn_burst_count: usize },
CrossTierPrivilegeViolation { account_rid: u32, from: AdminTier, to: AdminTier },
PassTheHashLateralFanOut { source_ip: u32, distinct_targets: usize },
}
pub struct LateralMovementDetector {
tgs_spn_history: HashMap<u32, Vec<u64>>,
ntlm_target_fanout: HashMap<u32, HashSet<u32>>,
window_sec: u64,
}
impl LateralMovementDetector {
#[must_use]
pub fn new(window_sec: u64) -> Self {
Self {
tgs_spn_history: HashMap::new(),
ntlm_target_fanout: HashMap::new(),
window_sec,
}
}
/// Evaluates an incoming AD authentication telemetry event for privilege escalation & lateral movement.
pub fn inspect_event(&mut self, ev: &AuthTelemetryEvent) -> Vec<ThreatSignal> {
let mut signals = Vec::new();
// 1. Enforce strict Tier boundary: Tier 0 credentials must NEVER authenticate to Tier 2 workstations
if ev.account_tier == AdminTier::Tier0DomainControl && ev.target_tier == AdminTier::Tier2Workstation {
signals.push(ThreatSignal::CrossTierPrivilegeViolation {
account_rid: ev.account_sid_rid,
from: ev.account_tier,
to: ev.target_tier,
});
}
// 2. Detect Kerberoasting (Event 4769 with RC4-HMAC etype 0x17 against SPNs)
if ev.event_id == 4769 && ev.spn_requested && ev.kerberos_etype == ETYPE_RC4_HMAC {
let timestamps = self.tgs_spn_history.entry(ev.source_ip).or_default();
timestamps.push(ev.timestamp_sec);
let cutoff = ev.timestamp_sec.saturating_sub(self.window_sec);
timestamps.retain(|&t| t >= cutoff);
if timestamps.len() >= 3 {
signals.push(ThreatSignal::KerberoastingRc4Downgrade {
source_ip: ev.source_ip,
spn_burst_count: timestamps.len(),
});
}
}
// 3. Detect Pass-the-Hash lateral fan-out (Event 4624 Type 3 NTLM with local admin RID 500)
if ev.event_id == 4624 && ev.is_ntlm_network_logon && ev.account_sid_rid == 500 {
let targets = self.ntlm_target_fanout.entry(ev.source_ip).or_default();
targets.insert(ev.target_host_id);
if targets.len() >= 2 {
signals.push(ThreatSignal::PassTheHashLateralFanOut {
source_ip: ev.source_ip,
distinct_targets: targets.len(),
});
}
}
signals
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detects_rc4_kerberoasting_and_tier_violation() {
let mut detector = LateralMovementDetector::new(60);
for i in 0..3 {
let ev = AuthTelemetryEvent {
timestamp_sec: 1000 + i,
source_ip: 0x0A00_0115,
target_host_id: 1,
account_sid_rid: 1104,
account_tier: AdminTier::Tier2Workstation,
target_tier: AdminTier::Tier0DomainControl,
event_id: 4769,
kerberos_etype: ETYPE_RC4_HMAC,
is_ntlm_network_logon: false,
spn_requested: true,
};
let alerts = detector.inspect_event(&ev);
if i == 2 {
assert_eq!(alerts.len(), 1);
}
}
}
}