hunt-ntlm-info について
NTLM情報漏えいを調査するセキュリティテスト用スキルです。匿名のNTLMチャレンジを検査し、ホストやドメイン情報の解析、影響評価、緩和策の確認を案内します。
主な機能
- 01匿名NTLMチャレンジの検査
- 02NTLM Type-2メッセージの解析
- 03ホスト名とADドメイン情報の特定
- 04露出状況と影響の評価
- 05緩和策の確認
活用シーン
- 01公開IIS、SharePoint、Exchangeの検査
- 02匿名エンドポイントによるAD構成漏えいの確認
- 03認証攻撃チェーン向けの偵察情報の補完
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ elementalsouls/ claude-bughunter --skill hunt-ntlm-infoインストール後、Claude Code で/hunt-ntlm-infoを入力して読み込まれたか確認します。
詳細
最重要の標的
NTLM 情報漏えいは、攻撃の文脈と組み合わせると中程度の深刻度に該当する問題です。漏えいそのものは意図されたプロトコルの動作(RFC に準拠した NTLMSSP チャレンジ)ですが、インターネットに公開されたエンタープライズインフラでは、攻撃の次の段階に向けた正確な偵察情報を提供します。特に価値の高い標的は次のとおりです。
- インターネットからアクセス可能な IIS/SharePoint/Exchange/OWA で、二重認証(Forms + NTLM、または NTLM + Kerberos)を使用しているもの
- NTLM を基盤とする AD 認証を使用する、インターネット公開の Citrix NetScaler/VMware Horizon View ゲートウェイ
- Lync/Skype for Business/Teams On-Prem のエッジサーバー
- NTLM で保護された管理者用パスを持つ WSUS/Windows Update Services
- NTLM をプロキシする CIFS 形式のファイル共有プロキシ(HCL Sametime、IBM Notes Domino)
- パブリックゾーンの IIS バインドで NTLM を有効にしたままの レガシー SharePoint ファーム
この情報が役立つ理由:
- 内部 AD ドメインの開示(親フォレストのマッピング。例:
customer.parent-corp.example→ corporate-AD ツリー内のテナント) - Windows のデフォルトのホスト名の開示(
WIN-XXXXXXXXXXXのパターンは、急いでプロビジョニングされたことを示唆し、デフォルトのサービスアカウントのパスワードが使われている可能性があります) - タイムスタンプの漏えい(NTLMv2 ハッシュのクラッキングを高速化するために使用)
hunt-auth-bypassLegacy-Protocol Matrix と組み合わせた、認証情報のスプレー攻撃向け攻撃マップの直接的な強化
攻撃対象領域のシグナル
NTLM が利用可能であることを示すレスポンスヘッダー:
WWW-Authenticate: NTLM
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM, Negotiate
WWW-Authenticate: Negotiate, NTLM
NTLM が公開されていることが多い URL パターン:
/_api/web/CurrentUser (SharePoint REST)
/_vti_bin/*.asmx (SharePoint legacy SOAP)
/EWS/Exchange.asmx (Exchange Web Services)
/Autodiscover/Autodiscover.xml (Exchange autodiscover)
/owa/ (Outlook Web App)
/Microsoft-Server-ActiveSync (ActiveSync)
/PowerShell (Exchange Mgmt Shell over HTTPS)
/api/v3/ (TeamCity, Atlassian)
/wsus/ (Windows Server Update Services)
/manager/html (some Tomcat behind IIS)
/iisstart.htm (default IIS, sometimes reveals NTLM upstream)
技術スタックのシグナル:
- パブリックインターネット上の IIS(フロントエンドが Forms の場合でも、ほぼ常に NTLM に対応しています)
- SharePoint Web フロントエンド(ほぼ常に Forms + NTLM の二重認証を使用します)
- Exchange エッジトランスポート
- サーバーヘッダー
Microsoft-HTTPAPI/2.0、Microsoft-IIS/*、IIS/*
手順に沿った調査方法
-
匿名でアクセスできるすべてのエンドポイントに対して、
WWW-Authenticate: NTLMを確認します。 通常の GET リクエストを送信し、レスポンスヘッダーを調べます。NTLM が提示された場合は、次に進みます。 -
有効な NTLMSSP Type-1 メッセージを匿名で送信します。 以下の Type-1 の base64 は、サーバーから NetBIOS ドメイン情報とワークステーション情報を要求します:
Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==これは、ネゴシエートフラグ
NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_56 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_TARGET_INFOを含む標準的なテスト用 Type-1 です。OS Versionフィールド(06 01 B1 1D 00 00 00 0F)は Windows 7 ビルド 7601 を示し、ほぼすべての NTLM レスポンダーで受け入れられます。 -
Python requests や curl の単発リクエストではなく、キープアライブ対応の生ソケットを使用します。 多くの HTTP ライブラリは、Type-1 の送信から Type-2 の受信までの間に接続を閉じます。次のいずれかを使用します:
Connection: keep-aliveを明示的に設定した Burp Repeater- Burp
mcp__burp__send_http1_request(キープアライブをネイティブに処理します) - Python の生
socket+ssl.wrap_socket(「ペイロード」セクションを参照)
-
WWW-Authenticate: NTLM <base64>レスポンスヘッダーから Type-2 チャレンジを解析します。 値を Base64 デコードします。構造は MS-NLMP に準拠する NTLMSSP です:- バイト 0-7:リテラル値
NTLMSSP\0 - バイト 8-11:MessageType =
\x02\x00\x00\x00 - バイト 12-19:TargetName SecurityBuffer(長さ、割り当て長、オフセット)
- バイト 20-23:NegotiateFlags
- バイト 24-31:Server Challenge(8 バイト。オフライン解析に有用)
- バイト 40-47:TargetInfo SecurityBuffer(長さ、割り当て長、オフセット)
- TargetInfo 本文:
AV_PAIRS配列(AvId u16、AvLen u16、Value)
- バイト 0-7:リテラル値
-
AV_PAIRS をデコードします。 確認する AvId は次のとおりです:
1= NetBIOS コンピューター名2= NetBIOS ドメイン名3= DNS コンピューター名(応答サーバーの FQDN)4= DNS ドメイン名(AD ドメイン)5= DNS ツリー名(AD フォレストのルート)7= タイムスタンプ(FILETIME。NTLMv2 ハッシュのリレーや解析に有用)9= ターゲット名(新しい NTLMSSP の場合)
-
調査結果を重大度レベルに割り当てます:
- インターネットに公開されている + デフォルトの
WIN-XXXXXXXXXXXホスト名 + 企業の AD ツリーの開示 → 中 - インターネットに公開されている + 名前付きサーバーのホスト名(
SPWEB01.corp.example)+ 企業の AD ツリー → 低~中 - イントラネット限定 + 何らかの開示 → 参考情報
- 同じホストで
hunt-auth-bypassのレガシープロトコルマトリックスの調査結果と組み合わせる → 攻撃者が UPN/SAM 形式をすぐに利用できるため、認証バイパスの調査結果の重大度を引き上げます
- インターネットに公開されている + デフォルトの
-
タイムスタンプを確認します。
AV[7]がDate:ヘッダーから約 5 秒以内の現在の FILETIME を返す場合、システムクロックは同期されています。これは Kerberos ゴールデンチケットの偽造に役立つ情報です(バグバウンティの対象外ですが、レッドチームには関係します)。 -
サブドメイン列挙の結果と照合します。 DNS Tree 名から、親フォレストが明らかになることがよくあります。たとえば、
customer.parent-corp.exampleは、顧客が別のテナントではなく、企業の親 AD 内のサブドメインであることを示しています。これはプライバシーやネットワーク構成の開示に関する重大度引き上げにつながり、プログラムによっては中として受け入れられることがあります。
ペイロードと検出パターン
汎用 NTLM Type-1 匿名プローブ(curl と生ソケットのフォールバック):
# Most one-shot curl runs DON'T return Type-2 because the connection closes.
# Use this as a quick probe to confirm NTLM is offered:
curl -sk -I -H "Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==" \
"https://target.example/_api/web/CurrentUser" 2>&1 | grep -i "WWW-Authenticate"
Burp send_http1_request(Type-2 の全データ取得に推奨):
GET /_api/web/CurrentUser HTTP/1.1
Host: target.example
Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==
Connection: keep-alive
User-Agent: Mozilla/5.0
Python の生ソケット + AV_PAIR デコーダー:
import socket, ssl, base64, struct, re
from datetime import datetime, timezone
HOST = "target.example"
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
s = ctx.wrap_socket(socket.create_connection((HOST, 443)), server_hostname=HOST)
s.sendall(
f"GET /_api/web/CurrentUser HTTP/1.1\r\n"
f"Host: {HOST}\r\n"
"Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==\r\n"
"User-Agent: Mozilla/5.0\r\nConnection: keep-alive\r\n\r\n".encode()
)
data = b""
while True:
chunk = s.recv(8192)
if not chunk: break
data += chunk
if b"\r\n\r\n" in data: break
m = re.search(rb"WWW-Authenticate:\s*NTLM\s+([A-Za-z0-9+/=]{20,})", data, re.I)
if m:
b = base64.b64decode(m.group(1).decode("ascii"))
assert b[:8] == b"NTLMSSP\x00"
tn_len, _, tn_off = struct.unpack_from('<HHI', b, 12)
ti_len, _, ti_off = struct.unpack_from('<HHI', b, 40)
print(f"TargetName: {b[tn_off:tn_off+tn_len].decode('utf-16-le', errors='ignore')!r}")
av_types = {1:'NetBIOS Computer Name', 2:'NetBIOS Domain Name',
3:'DNS Computer Name', 4:'DNS Domain Name',
5:'DNS Tree Name', 7:'Timestamp', 9:'Target Name'}
i = 0
ti = b[ti_off:ti_off+ti_len]
while i < len(ti):
av_id, av_len = struct.unpack_from('<HH', ti, i)
if av_id == 0: break
val = ti[i+4:i+4+av_len]
if av_id == 7:
ts = struct.unpack('<Q', val[:8])[0]
secs = (ts - 116444736000000000) / 10000000
vs = datetime.fromtimestamp(secs, tz=timezone.utc).isoformat()
else:
vs = val.decode('utf-16-le', errors='ignore')
print(f" AV[{av_id}] {av_types.get(av_id, '?'):28s}: {vs!r}")
i += 4 + av_len
この種の調査結果では Burp Collaborator は不要です。データ漏えいは OOB 経由ではなく、同期レスポンス内で発生します。
共通する根本原因
-
パブリックゾーンの IIS バインドで二重認証が有効になっている。 管理者が、フォーム認証を本来のエントリーポイントとしているにもかかわらず、インターネットに公開された IIS サイトで NTLM を有効にしたままにしています。内部ユーザーは SSO を利用できますが、外部の攻撃者には AD トポロジーが漏えいします。
-
既定の IIS アプリケーションプール ID が
ApplicationPoolIdentityのままになっている。 既定のホスト名と組み合わさると、初回起動時の設定以降、プロビジョニングが進んでいないことを示します。 -
サーバー名が Windows インストーラーによって生成されたホスト名のままになっている。 Microsoft の既定の
WIN-XXXXXXXXXXXという 11 文字のパターンは、すぐに見分けられる手掛かりです。古いマシンでは、WORKGROUP\WIN-...になっていることもあります。 -
ゾーン分離なしで、サブドメインが企業フォレストに参加している。 欧州のインテグレーターの事例では、欧州の輸入業者の SharePoint テスト環境が企業のグローバル AD 内の子ドメインであり、そのことが NTLM DNS ツリー名から判明しました。顧客は
customer.parent-corp.exampleを運用上分離された環境にする意図だったと思われますが、NTLM Type-2 により、プローブを行う誰もがフォレストへの所属を把握できます。 -
IIS Extended Protection が有効になっていない。
<system.webServer><security><authentication><windowsAuthentication extendedProtection>がNone(既定値)の場合、NTLM チャレンジはすべての匿名クライアントに送信されます。Requiredに設定すると、NTLM は認証済みの呼び出し元に制限され、AV ペアの漏えいが軽減されます。 -
インターネットに公開されたサイトで、
WindowsAuthenticationがapplicationHost.configから削除されていない。 SharePoint Central Admin では、SP ゾーンの設定でフォーム認証のみを有効にしていても、これが有効なままになっていることがあります。
バイパス手法
このスキルが説明するのは情報漏えいであり、認証のバイパスではありません。「バイパス」に関する問いは、正当な NTLM 認証を許可したまま、この AV ペアの漏えいを防ぐにはどうすればよいか? ということです。
| 防御策 | 有効性 |
|---|---|
| パブリック IIS バインドで NTLM を完全に無効化する(フォーム認証のみ) | 最善 — 攻撃対象領域をなくします |
| IIS Extended Protection = Required | NTLM チャレンジを認証済みの呼び出し元に制限し、AV ペアの漏えいを軽減します |
リバースプロキシで匿名応答から WWW-Authenticate を除去する | 有効な場合もありますが、正当なクライアントに支障が出ます |
| Type-1 → Type-2 エンドポイントにレート制限を適用する | 情報漏えいは防げず、列挙を遅らせるだけです |
Windows ホスト名を WIN-XXXXXXXXXXX から変更する | 「プロビジョニングの手抜き」という手掛かりをなくしますが、漏えいは防げません |
| SP/Exchange ファームを、企業とのクロストラストがない子 AD に移す | フォレストの情報漏えいを軽減しますが、漏えい自体は防げません |
攻撃者にとって、「バイパス」は必要ありません。漏えいそのものが発見事項です。
ゲート 0 の検証
レポートを作成する前に、次の点を確認してください。
-
この情報漏えいによって、攻撃者は今すぐ何ができるか?
- インターネットに公開されており、既定のホスト名と企業フォレストが判明している → 中:攻撃者は
hunt-auth-bypassのマトリクスプローブに使える UPN 形式を把握でき、サーバーに既定のサービスアカウントが残っている可能性が高いことも分かります。 - イントラネット専用、または NetBIOS 名のみ → 情報提供。
- インターネットに公開されており、既定のホスト名と企業フォレストが判明している → 中:攻撃者は
-
プログラムは、影響を連鎖させていない情報漏えいの報告を受け付けるか?
- 多くのプログラム(Microsoft、大規模エンタープライズ VDP)は、漏えいした情報に内部 AD トポロジーが含まれる場合、受け付けます。
- 多くのプログラム(Shopify、GitHub)は、影響を連鎖させていない情報漏えいを却下します。
- 提出前にプログラムのスコープを確認してください。判断が難しい場合は、
hunt-auth-bypassの Tier-A 発見事項と組み合わせてください。
-
新しいシェルから 5 分以内に再現できるか?
- 上記の Python スニペットが標準的な再現方法です。レポートにはそのまま記載してください。
実際の影響例
シナリオ A — 親会社の企業 AD 内にある Enterprise SharePoint
対象:https://target-portal.example/ — システムインテグレーターが運営する企業向けディーラーポータル(テスト用ミラー)です。
/_api/web/CurrentUser に匿名の Type-1 メッセージを送信したところ、AV_PAIRS をデコードすると次の内容を含む Type-2 チャレンジが返されました。
NetBIOS Domain Name: <CustomerName>
NetBIOS Computer Name: WIN-XXXXXXXXXXX
DNS Domain Name: customer.parent-corp.example
DNS Computer Name: WIN-XXXXXXXXXXX.customer.parent-corp.example
DNS Tree Name: customer.parent-corp.example
Timestamp: 2026-05-13T15:55:37.922Z
エスカレーションにつながる経路は 3 つあります。
- Windows インストーラーのデフォルトのホスト名(
WIN-XXXXXXXXXXX) — OS のインストール後、サーバーの名前が変更されていません。プロビジョニングがずさんであることを強く示しています。SQL バックエンドのサービスアカウントにデフォルトのパスワードが使われていたり、WSUS がデフォルト設定のままだったりする可能性があります。 - 企業の親会社 AD 内のサブドメイン(
customer.parent-corp.example) — 顧客は<ParentCorp>のグローバル Active Directory 内の子ドメインです。このテストファームが侵害された場合、企業の親会社との信頼関係を介して影響が及ぶ可能性があります。 - UPN の形式が判明している —
hunt-auth-bypassによって/_vti_bin/Authentication.asmxに匿名で利用できるブルートフォースエンドポイントが発見されていることと合わせると、攻撃者は認証情報の形式([email protected]または<CustomerName>\firstname.lastname)と、回数制限のない送信エンドポイントの両方を把握しています。
報告された深刻度:中。Authentication.asmx への匿名ブルートフォースを組み合わせると、攻撃全体の深刻度は「重大」になるとの注記が付されています。
シナリオ B — NTLM で保護された EWS を持つ Exchange エッジ
対象:https://mail.example.com/EWS/Exchange.asmx。Type-1 プローブに対し、DNS Tree Name が corp.example.com、DNS Computer Name が MAIL01.corp.example.com の Type-2 が返されます。これにより、Exchange エッジが DMZ から隔離された AD で稼働しているのではなく、企業 AD にドメイン参加していることが確認できます。対応する hunt-mfa-bypass/hunt-auth-bypass の一連の手法を持つ攻撃者にとって、UPN 形式とサーバー名の形式が漏えいしていることで、偵察の手順を省き、認証情報のスプレー攻撃を効率化できます。報告された深刻度は、プログラムによって「低〜中」です。
シナリオ C — 意図的なイントラネット限定の漏えい(脆弱性報告の対象外)
対象:https://intranet.corp.example(明らかに社内向けで、VPN の背後にあります)。Type-1 に対して AV ペアの全セットが返されます。報告対象ではありません。これはイントラネットで想定される NTLM の動作であり、すでに nltest /dsgetdc:corp.example.com で同じ情報を確認できる、認証済み VPN ユーザーに対する情報開示です。該当なしとして対応を終了してください。
関連するスキルとチェーン
hunt-sharepoint— SharePoint ファームはデフォルトで/_vti_bin/上に匿名の Type-2 チャレンジを返します。これは内部 AD トポロジーを取得する最も信頼性の高い方法の 1 つです。チェーンのプリミティブ:SharePoint を発見 →/_vti_bin/Lists.asmxで NTLM Type-2 を取得 →hunt-ntlm-infoで AV_PAIR をデコード → 内部フォレスト名を取得 → そのフォレストに紐づく Entra テナントに対してm365-entra-attackで ROPC スプレーを実施。m365-entra-attack— 漏えいした NetBIOS ドメインと UPN サフィックスは、信頼性の高いパスワードスプレーに欠かせない情報です。チェーンのプリミティブ:NTLM Type-2 からcorp.example.comDNS ツリーを取得 →https://login.microsoftonline.com/corp.example.com/.well-known/openid-configurationを介して Entra テナントと照合 → 特定したテナントに対してm365-entra-attackで AADSTS エラー差分を利用したユーザー名列挙を実施。hunt-aspnet— ASP.NET を実行する IIS サイトでは、管理パスで NTLM が公開されていることがよくあります。チェーンのプリミティブ:/owa/、/ecp/、/rpc/、/aspnet_client/で NTLM Type-2 を取得 → IIS と ASP.NET のバージョンを確認 → 同じホスト上でhunt-aspnetによる ViewState /.axdの列挙を実施。offensive-osint— ホスト名パターンWIN-XXXXXXXXXXXは、手軽なプロビジョニングを示し、ほかにもセキュリティ衛生上の弱点があることを予測させます。チェーンのプリミティブ:NTLM Type-2 からデフォルトインストーラーのホスト名を取得 → 成熟度の低い環境としてフラグを立てる → この組織ではoffensive-osintによる詳細な偵察(証明書の透明性、GitHub からの漏えい、侵害データコーパスとの相関分析)が高い成果につながります。triage-validation— ほとんどの NTLM 情報開示の指摘は、「悪用可能か」という 7-Question Gate の段階で却下されます。トポロジーのみの開示は Low / Informational です。チェーンのプリミティブ:すべての NTLM 情報に関する指摘を、報告書に記載する前にtriage-validationで検証します。(a)スプレーを効率化する UPN 形式が漏えいする場合、または(b)本番環境のホスト名マッピングが漏えいする場合にのみ報告してください(チェーンのストーリーにはredteam-report-templateを使用します)。