コンテンツにスキップ

Pirate で学ぶ Windows / AD の仕組み

このページでは、Pirate の Writeup に登場した仕組みを取り上げます。攻略の流れを追う場合は Writeup を、Responder や RBCD などの役割を確認する場合はこのページを参照してください。

Responder は、Windows の名前解決が別の方式へ切り替わる際の問い合わせを待ち受けるツールです。LLMNR、NBT-NS、mDNS、WPAD などの問い合わせに応答し、SMB や HTTP を通じた NTLM 認証を引き出します。

典型的には次の流れです。

Windows host -> 名前解決に失敗
Windows host -> LLMNR/NBT-NS で周囲に問い合わせ
Responder -> その名前は自分だと応答
Windows host -> SMB/HTTP などで接続
Responder -> NTLM challenge/response を取得

この流れが成立するには、対象から待ち受けアドレスへ通信できる必要があります。HTB のようにルーティングやピボットを挟む環境では、とくに戻りの経路を確認します。

Pirate では、最終的な成功経路は Responder による hash capture ではなく、ntlmrelayx の SMB listener に WEB01$ を戻して LDAPS に relay する形でした。

Coercer は、Windows の RPC インターフェースを使い、対象から外部への認証を発生させるツールです。対象に UNC パスを渡してアクセスさせることで、computer account の NTLM 認証を待ち受け側へ送らせます。

今回のイメージは次です。

attacker -> Coercer -> WEB01 の RPC endpoint を叩く
WEB01 -> \\<listener>\share\file.txt へアクセスしようとする
WEB01 -> listener に WEB01$ として NTLM 認証する
ntlmrelayx -> その NTLM を LDAPS/DC01 に relay

Coercer の ERROR_BAD_NETPATH や NO_AUTH_RECEIVED は、method 単位では失敗に見えても、別 method が実際には認証を発生させていることがあります。最終判断は ntlmrelayx 側に PIRATE/WEB01$ ... SUCCEED が出たかで行うのが正確です。

ntlmrelayx は攻撃側で SMB や HTTP の接続を待ち受け、受け取った NTLM 認証を別のサービスへ中継します。

今回の成功形は次です。

WEB01$ --SMB NTLM--> attacker:445 / ntlmrelayx
ntlmrelayx --relays NTLM--> ldaps://DC01
DC01 LDAP modify -> WEB01$ の RBCD に MS01$ を追加

coercer -l は「WEB01 が接続し返す宛先」です。ここを古い VPN IP や WEB01 から到達できない IP にすると、Coercer 側では RPC method を呼べても、ntlmrelayx には何も来ません。

HTTP/WebDAV relay を試す場合は WebClient service や firewall の影響を受けます。Pirate では HTTP callback は成立せず、SMB callback を attacker VPN IP に向ける形で成功しました。

MS01$ は単なる computer account ではなく、複数の重要なシグナルが重なっていました。

  • Domain Secure Servers の member
  • Domain Secure Servers が gMSA password を読める
  • MS01$ は pre-created computer account
  • MS01$ の初期 password pattern が ms01

このため、MS01$:ms01 を取ると gMSA password が読めます。さらに、relay 後の RBCD でも MS01$ を delegation 元として使えるため、攻略全体の pivot account になりました。

RBCD の成功メッセージが示すこと

Section titled “RBCD の成功メッセージが示すこと”

このメッセージは、WEB01$ の msDS-AllowedToActOnBehalfOfOtherIdentity に MS01$ が追加されたことを意味します。

簡略化すると次の意味です。

WEB01$:
「MS01$ が、任意ユーザーを代理して WEB01 の service ticket を取ってよい」

impersonate は「なりすます」というより、Kerberos の文脈では「ユーザーを代理する」に近いです。MS01$ は Administrator を代理し、cifs/WEB01.pirate.htb の service ticket を取得しました。

S4U の役割は次です。

  • S4U2self: service account が任意ユーザーへの自分宛て service ticket を得る。
  • S4U2Proxy: その user context を使って別 service への ticket を得る。

RBCD があると、S4U2Proxy の宛先が target machine 側の許可リストで制御されます。

WriteSPN は servicePrincipalName attribute を変更できる権限です。よくある使い方は、任意 SPN を user に付けて Kerberoast する targeted Kerberoast です。

Pirate ではそれより強い使い方をしました。

a.white_adm は HTTP/WEB01 に KCD 可能
IT は WEB01$ と DC01$ に WriteSPN
HTTP/WEB01 を WEB01$ から DC01$ へ移す
KDC は HTTP/WEB01 を DC01$ の SPN として解決
a.white_adm の KCD が実質 DC01 に向く

これが SPN-jacking です。サービス名は WEB01 のままですが、SPN の所有者が DC01$ に変わるため、DC01 が復号できる ticket を取得できます。

SPN-jacking では AD object の servicePrincipalName attribute を変更する必要があります。これは LDAP modify operation で行えます。

ldapmodify を使った理由は次です。

  • delete と add を明示できる。
  • servicePrincipalName 全体の replace ではなく、必要な値だけを移動できる。
  • LDIF にすると何を変更したかが記録として残る。
  • SPN 復元用の LDIF も作りやすい。

bloodyAD set object でも属性変更はできますが、実装上は attribute 全体の replace になるため、既存 SPN を壊さないように現在値を控えて完全なリストで置換する必要があります。

hashcat の rule は wordlist の各候補に変形を加える仕組みです。例えば、以下のような変形を大量に生成します。

password -> Password
password -> password1
password -> password!
summer -> Summer2026!

best64.rule は John the Ripper 側にある有名な小さめの rule set です。hashcat で John の rule を使うと、対応していない rule 行が skip されることがあります。Pirate では Kerberoast hash は取得できましたが、rockyou と rule では a.white_adm の password は割れませんでした。

Muffin が表示されたのは候補生成の進捗表示であり、cracked password ではありません。正しく割れているかは hashcat --show で確認します。