
GoによるADWS(net.tcp/9389)経由のActive Directory偵察および読み取り専用セキュリティ監査
adit は、シングルバイナリの Active Directory 偵察 および 読み取り専用のセキュリティ監査ツールであり、LDAP ではなく ADWS (Active Directory Web Services、TCP/9389) を介してドメインコントローラーと通信します。
adit とは鉱山への水平坑道、つまり静かな侵入経路のことです。LDAP/389 ではなく ADWS 経由で AD をクエリすることで、トラフィックは WCF の net.tcp フレーミングによるバイナリ XML の SOAP となり、一般的でないポートを使用するため、従来の LDAP に比べて検査・フィルタリング・シグネチャ検知される可能性がはるかに低くなります。それでいて同じディレクトリデータを取得できます。adit は ADWS プロトコルスタック全体を Go で実装しており、外部ランタイム依存はありません。
┌────────────┐ net.tcp/9389 ┌──────────────┐
│ adit │ ───────────────▶ │ ADWS on DC │ ──▶ local LDAP
│ (Linux) │ NMF · NNS · │ (port 9389) │
│ │ NBFSE · SOAP └──────────────┘
└────────────┘
adit は防御/監査および許可された評価のためのツールです。評価を許可されている ディレクトリに対してのみ実行してください。
| 機能 | 詳細 |
|---|---|
| トランスポート | WCF net.tcp (TCP/9389) 上の ADWS — MC-NMF フレーミング、MS-NNS ハンドシェイク、MC-NBFS/NBFSE バイナリ XML、WS-Enumeration/WS-Transfer SOAP |
| 認証 | NTLMv2 (sign + seal) および Kerberos (ccache / keytab / パスワード; RFC 4121 封印 GSS) |
| 偵察コレクター | 31 個のモジュール (下記参照) → モジュールごとの CSV |
| レポート | スタイル付きマルチシート XLSX ワークブック + 自己完結型 HTML ダッシュボード (検索/ソート、重大度バッジ、スクロールスパイ) |
| セキュリティ監査 | 30 個の読み取り専用ルール (ADCS ESC1–4/9 を含む) → 重大度でランク付けされた JSON。ダッシュボードにも表示 |
| プロキシ / ジャンプホスト | HTTP CONNECT、SOCKS5/5h、SOCKS4/4a (プロキシ認証 + リモート DNS 対応) |
| ページング | サーバー側 WS-Enumeration Pull ページング、ページサイズ設定可能 |
| オフラインレポート | 以前に収集した CSV から XLSX/HTML を再構築、DC 不要 |
| 依存関係 | 純粋な Go。LDAP ライブラリ、.NET、外部サービスは不要 |
forest、domain、trusts、sites、subnets、schemahistory、dcs、
users、userspns、groups、computers、computerspns、ous、gpos、
gplinks、passwordpolicy、fgpp、dnszones、dnsrecords、kerberoastable、
asreproastable、krbtgt、adcs、cas、laps、protectedgroups、
groupmembers、gmsa、dmsa、printers、bitlocker
ADCS (adcs) は ESC1–ESC4/ESC9 をフラグ付けします。laps は各パスワードを読み取れる
ユーザーを報告します。protectedgroups は Protected Users を監査します。現在の
リストを表示するには adit -list-modules を実行してください。
-audit は 30 個の読み取り専用ルールを実行します。検出結果にはルール ID、重大度、影響を受ける
オブジェクト、証拠、および修復策が含まれ、Adit-Audit.json に書き込まれます (また、
-collect と組み合わせた場合は、ダッシュボードの先頭に表示される「Audit Findings」セクションにも
書き込まれます)。エンジンは、偵察コレクターが読み取れる場合でも、シークレット属性値 (LAPS / gMSA /
BitLocker) を決して読み取りません。
| ルール | 重大度 | 検出内容 |
|---|---|---|
| AD-DOM-010 | Critical | 非Tier-0プリンシパルが保持するDCSync(レプリケーション)権限 |
| AD-ACL-001/005/006/007/011–016 | Critical | 特権オブジェクトに対する危険な制御(GenericAll/Write、WriteDACL/Owner、ForceChangePassword、Write SPN / KeyCredentialLink / member / AllowedToAct) |
| AD-SDH-001/002 | Critical | AdminSDHolderの予期しない制御 / 所有者 |
| AD-CS-001 | Critical–Medium | ESC1 — 証明書テンプレートが登録者指定のサブジェクトを許可 |
| AD-CS-002 | Critical–Medium | ESC2 — Any-Purpose / EKUなしの証明書テンプレート |
| AD-CS-003 | High–Medium | ESC3 — Certificate Request Agentテンプレート |
| AD-CS-004 | High | ESC4 — 証明書テンプレートの脆弱なアクセス制御 |
| AD-CS-009 | High | ESC9 — 証明書テンプレートにセキュリティ拡張がない |
| AD-CS-005 | Critical/High | ESC5 — PKIオブジェクト(NTAuthCertificates、CAストア、CAオブジェクト)の危険な制御 |
| AD-CS-006 | Info | AD CSが存在 — ESC6/ESC7/ESC8はホストレベルの検証が必要(ADWS経由では観測不可) |
| AD-DOM-008 | High | ドメイン全体で可逆パスワード暗号化が有効 |
| AD-USR-001 | High | Kerberos事前認証が無効(AS-REPロースト可能) |
| AD-USR-009 | High | アカウントがDES暗号化のみを使用 |
| AD-CMP-006 | High | 非DCでの無制約委任 |
| AD-KCL-001 | High | 特権アカウント上のKey Credential(シャドウクレデンシャル) |
| AD-KRB-001 | High | krbtgtパスワードが古い |
| AD-DOM-005 | Medium | マシンアカウントクォータ > 0(任意のユーザーがコンピューターを参加可能) |
| AD-USR-002 | Medium | Kerberoast可能なサービスアカウント(特権の場合はHigh) |
| AD-USR-005 | Medium | PASSWD_NOTREQDが設定 |
| AD-USR-006 | Medium | 特権アカウントのパスワードが無期限 |
| AD-USR-011 | Medium | 特権アカウントのパスワードが古い |
| AD-CMP-008 | Medium | リソースベースの制約付き委任が構成済み |
| AD-CMP-012 | Medium | レガシー / サポート対象外のオペレーティングシステム |
| AD-GRP-009 | Medium | 特権グループ内の外部セキュリティプリンシパル |
| AD-GRP-020 | Medium | primaryGroupIDによる隠れた特権メンバーシップ |
| AD-TRU-001/003 | High/Medium | SIDフィルタリングなし / SID履歴ありの信頼 |
| AD-DNS-003/004 | Medium/Low | WPAD / ISATAPレコードの存在 |
| AD-CMP-011 | Low | 古いコンピューターアカウント |
| AD-INT-005 | High | sIDHistoryに特権SIDが含まれる |
| AD-USR-020 | High | userPassword / unixUserPasswordに保存された復元可能なパスワード |
| AD-USR-021 | High | description / info / commentに残された可能性のあるパスワード(ヒューリスティック) |
| AD-DOM-012 | High/Medium | Pre-Windows 2000 Compatible Access内のEveryone / Anonymous / Authenticated Users |
しきい値は調整可能です: -krbtgt-max-age、-priv-pwd-max-age、-stale-days。
ADCSに関する注記: ESC1–ESC5およびESC9はADWS経由でADオブジェクトから評価されます。ESC6 (
EDITF_ATTRIBUTESUBJECTALTNAME2)、ESC7(CAロールACL)、ESC8(Web 登録 / NTLMリレー)はCAホストのレジストリ/HTTPエンドポイントに存在し、 ADWS経由では観測できません —AD-CS-006はCAが存在することを示すため、ホスト上で (例えばCertipyを用いて)検証できます。
Go 1.26+ が必要です。その他のビルド依存関係はありません。
# Build the binary
go build -o adit ./cmd/adit
./adit -version
# …or run without installing
go run ./cmd/adit -h
# Cross-compile release archives for linux/windows/darwin (amd64+arm64) into dist/
bash scripts/build-release.sh
-fqdn は DC の実際の FQDN(IP ではない)である必要があります。ADWS の SOAP To ヘッダーは WCF の AddressFilter によってエンドポイントと照合されるためです。例えば、nslookup -type=SRV _ldap._tcp.dc._msdcs.<domain> <dc-ip> で確認できます。
adit -dc <host> -fqdn <dc-fqdn> -d <DOMAIN> -u <user> -p <pass> [flags]
# RootDSE handshake only (verifies auth + the full protocol stack)
adit -dc 10.0.0.10 -fqdn dc01.example.local -d EXAMPLE.LOCAL -u user -p 'pass'
# Run every collector -> ./report/CSV-Files/*.csv + Adit-Report.{xlsx,html}
adit -dc 10.0.0.10 -fqdn dc01.example.local -d EXAMPLE.LOCAL -u user -p 'pass' \
-collect all -o ./report
# A subset of collectors
adit -dc 10.0.0.10 -fqdn dc01.example.local -d EXAMPLE.LOCAL -u user -p 'pass' \
-collect users,groups,computers,kerberoastable
# Audit only -> Adit-Audit.json
adit -dc 10.0.0.10 -fqdn dc01.example.local -d EXAMPLE.LOCAL -u user -p 'pass' -audit
# Recon + audit: findings lead the XLSX + HTML dashboard
adit -dc 10.0.0.10 -fqdn dc01.example.local -d EXAMPLE.LOCAL -u user -p 'pass' \
-collect all -audit -o ./report
# Password (synthesises a krb5.conf from the domain + DC if none is present)
adit -dc 10.0.0.10 -fqdn dc01.example.local -d EXAMPLE.LOCAL -u user -p 'pass' -auth kerberos
# Existing ticket cache
KRB5CCNAME=/tmp/krb5cc_1000 adit -dc 10.0.0.10 -fqdn dc01.example.local \
-d EXAMPLE.LOCAL -u user -auth kerberos -ccache /tmp/krb5cc_1000
ADWS は Web サービス ですが HTTP ではありません — 9389 番ポート上で生の TCP を使用します — それでもプロキシはその TCP ストリームをトンネリングします。プロトコルが許す場合(SOCKS5/4a、HTTP CONNECT)、DC 名はプロキシ側で解決されるため、内部専用の名前でも機能します。
# SSH dynamic forward = a local SOCKS5 proxy
ssh -D 1080 -N jump-host &
adit -dc dc01.corp.internal -fqdn dc01.corp.internal -d CORP.INTERNAL \
-u user -p 'pass' -proxy socks5://127.0.0.1:1080 -collect all -audit -o ./report
# Other proxy forms
-proxy socks5://user:[email protected]:1080 # SOCKS5 with username/password auth
-proxy socks4a://10.0.0.5:1080 # SOCKS4a (remote DNS)
-proxy http://user:[email protected]:8080 # HTTP CONNECT (Basic auth)
-proxy https://proxy.corp:8443 # HTTP CONNECT over TLS to the proxy
-auth kerberos + パスワードの場合、KDC とのやり取りは依然として直接行われます。ジャンプホスト経由の場合は、まずチケットを取得し、-ccache / KRB5CCNAME を渡してください。