find-hidden-subdomains について
find-hidden-subdomains は、セキュリティや資産調査向けに、Certificate Transparency ログなどの受動的な情報源からサブドメインを探すスキルです。過去の記録と現在名前解決できるホストを区別し、共有証明書やマルチテナント環境による誤検出にも注意を促します。
主な機能
- 01Certificate Transparency ログの検索
- 02組織名からドメインを発見
- 03証明書 SAN と履歴の確認
- 04パッシブ DNS と名前解決の併用
- 05共有証明書による誤検出の識別
- 06情報源と状態を添えてホストを記録
活用シーン
- 01既知ドメインの過去のサブドメイン調査
- 02組織概要にないドメインの発見
- 03現在も名前解決する候補の選別
- 04ワイルドカード証明書と共有ホスティングの評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ useosint/ skills --skill find-hidden-subdomainsインストール後、Claude Code で/find-hidden-subdomainsを入力して読み込まれたか確認します。
同梱ファイルreference/name-pattern-triage.mdreference/subdomain-sources.md
詳細
隠れたサブドメインを見つける
組織が存在を忘れていたホストこそ、見つける価値があります。その大半は、誰かが TLS 証明書を要求した時点で自らの存在を知らせています。Certificate Transparency を使えば、それらを検索可能で永続的な履歴インデックスにできます。無料で、完全にパッシブです。初心者が陥りがちな間違いは、CT で見つかったものを稼働中のホストとして扱うことです。取得した情報の大半は名前解決できません。それも情報であり、ノイズではありません。
最初に使う情報源
| 手元にあるもの | まず使うもの | 理由 |
|---|---|---|
| アペックスドメイン | crt.sh のワイルドカードクエリ | 無料で最も広範囲をカバーし、長期間前に使われなくなった名前も含まれます |
| ワイルドカード証明書を使うドメイン | パッシブ DNS、次にアーカイブ | CT で確認できるのは *.example.com だけです |
| 命名規則の推測 | CT で規則を把握し、次にワードリストを使う | ブルートフォースを行う前に、パターンを把握できます |
| ドメインではなく組織名 | サブジェクトの組織名で証明書を検索 | 所有していると知らなかったドメインが見つかります |
| すでに手元にある証明書 | SAN、その後にシリアル番号と発行者 | SAN から関連ホストがわかり、シリアル番号から別の場所にある同一証明書を見つけられます |
| 現在稼働中 のホストだけが必要 | 候補リストを名前解決 | CT は本質的に履歴情報です。稼働状況を判定するのは DNS です |
CT の仕組み
CA は発行するすべての証明書を、追記専用で暗号学的に検証可能な公開ログに登録します。ログは署名付き証明書タイムスタンプを返し、主要なブラウザーは、認定ログの SCT を含まない公的に信頼された証明書を信頼しません。そのため、参加は任意ではありません。ブラウザーで機能する証明書は、ログに記録されています。
覚えておくべき重要な点は 3 つあります。
- 記録は削除されません。 ログは追記専用です。5 年前に証明書に記載されていたホスト名は、そのホストがなくなった後も残っています。
- プレ証明書と証明書の両方が表示されます。 CA は最終的な証明書の前にプレ証明書をログに記録するため、大半の名前は少なくとも 2 回表示されます。重複を除去してください。
- 対象は公的に信頼された証明書だけです。 プライベート/内部 CA、自己署名証明書、Cloudflare のオリジン証明書はログに記録されません。CT では、そうしたホストをまったく確認できません。
crt.sh
ウェブ UI では ?q= を指定します。% はワイルドカードで、output=json を指定すると機械可読な結果が得られます。
# every name ever seen in a cert covering example.com or a subdomain
curl -s 'https://crt.sh/?q=%25.example.com&output=json' \
| jq -r '.[].name_value' | sed 's/^\*\.//' | sort -u
# skip expired certs when you want a bias toward current infrastructure
curl -s 'https://crt.sh/?q=%25.example.com&output=json&exclude=expired' | jq -r '.[].name_value'
# an identity search on an organization string, which finds unknown domains
curl -s 'https://crt.sh/?q=Example+Corporation&output=json' | jq -r '.[].name_value'
q パラメーターは識別情報の検索に使われ、ドメイン名だけでなく組織名などのサブジェクトフィールドにも一致します。そのため、依頼内容に記載されていなかったドメインも見つけられます。
便利な JSON フィールドは、name_value(証明書に記載されたすべての名前。改行区切り)、common_name、issuer_name、not_before/not_after、serial_number、entry_timestamp、id です(証明書を読むには https://crt.sh/?id=<id> を開きます)。
crt.sh では、Postgres 経由でデータベースへの読み取り専用アクセスも利用できます。ホストは crt.sh、ポートは 5432、ユーザーは guest、データベースは certwatch です。これにより、JSON をページ送りする代わりに、証明書インデックスに対して実際の SQL を実行できます。これは共有の無料サービスです。クエリの範囲を絞り、過剰なクエリを実行するとアクセスが打ち切られる可能性があることを念頭に置いてください。
カバレッジやアクセス方式を含む、その他の CT フロントエンドについては、reference/subdomain-sources.md を参照してください。
SAN フィールドこそが成果です
ブラウザーは Common Name を無視します。実際に対象となるホスト名の一覧は、subjectAltName 拡張に記載されています。これを、1 つのチームが一緒に運用した内容を示すものとして読み取ります。
- 関連する名前がいくつか記載された証明書は、意図的にまとめられています。それらのホストは同じサービスに属し、おそらく同じ管理者が管理しています。
- 関連性のない名前が何十個も記載された証明書は、ホスティングプロバイダーや CDN がまとめた証明書です。**その名前は他の顧客のものであり、調査対象の資産ではありません。**これは、CT ベースの列挙で誤検出を引き起こす最大の要因です。
- 異なる登録可能ドメインの名前が 1 つの証明書に記載されている場合は、有力な発見です。1 人の運用者が両方を管理していることを意味し、買収、ブランド変更、非公開の関連ブランドが明らかになることがあります。結論を出す前に確認してください。上記の一括登録による落とし穴を参照してください。
- 内部名はここから頻繁に漏えいします。
jira、owa、vpn、*.corp.example.com、ラックやデータセンターのコードを含むホスト名、一般公開されたことのない製品コードネームなどです。
ワイルドカードは隠すものであり、明らかにするものではありません
*.example.com はすべてのサブドメインを対象にしますが、その名前を特定することはできません。通常は DNS-01 ACME 自動化と併せてワイルドカードに切り替えた組織は、その時点から CT 上で実質的に姿を消します。ワイルドカードを見つけた場合は、次の対応を取ります。
- ワイルドカードを使う前の、ホストごとの証明書が存在した期間について CT を調べます。
- 証明書ではなく DNS の応答を記録するパッシブ DNS に切り替えます。
- アーカイブや検索インデックスでホスト名を探します(
read-deleted-pages、google-like-a-spy)。 - 技術的な理由で独自の証明書が必要なホストを探します。ワイルドカードの対象より深い階層のラベル(
a.b.example.comには独自の証明書が必要です)や、異なる apex 上にあるホストなどです。
情報源を組み合わせてから、名前を解決する
CT からは履歴が得られます。パッシブ DNS からは観測された実態が得られます。ワードリストからは、どこにも公開されていない名前が得られます。これら 3 つをすべて使い、名前の出所ごとにラベルを付けてください。名前の出所によって付与できる信頼度が異なるためです。
subfinder -d example.com -all -silent -o passive.txt # aggregates many passive sources
amass enum -passive -d example.com # different source mix, slower
dnsx -l passive.txt -a -resp -silent # resolve candidates to A records
名前解決を行うと、候補は 3 つのグループに分かれます。アドレスに解決される名前、CNAME に解決される名前(転送先を確認してください。ベンダー名が示されており、参照先のない CNAME は報告すべきテイクオーバー候補です)、まったく解決されない名前です。無効な名前も発見事項になります。インフラの稼働時期や命名規則が明らかになり、後に再び解決されることもあります。
ブルートフォースの結果を信頼する前に、ワイルドカード DNS を検出してください。zzq7x-nonexistent.example.com のように、存在し得ないランダムな名前を解決します。応答があった場合、そのゾーンはすべての名前を解決するため、ブルートフォースで得たリスト全体が誤検出です。
明確に区別してください。CT、パッシブ DNS、検索エンジン、アーカイブへの照会は、対象に接触しません。公開再帰リゾルバーを介して候補名を解決する行為は、実質的に見えませんが、ルックアップは発生します。ワードリストによるブルートフォースは大量の DNS トラフィックを発生させ、対象の DNS プロバイダーから見えるほか、レート制限やブロックの対象になることもあります。httpx のようなツールで結果に HTTP プローブを行うのは、アクティブな行為です。対象のサーバーに接続します。作業範囲のメモにはブルートフォースとプローブを明記し、パッシブのみの作業では実施しないでください。
名前のパターンが示すもの
発見したすべてのホストを同等に扱わないでください。dev、staging、uat、vpn、legacy、old、管理パネルは、www とはリスクも、その後に必要な対応も大きく異なります。トリアージ表は
reference/name-pattern-triage.md にあります。
ここで問題が起きます
- バンドルされた証明書とマルチテナント証明書。 共有ホスティングや CDN の証明書では、無関係な顧客が1つの証明書にまとめられていることがあります。証明書に記載された他の名前が、対象に属していると考えられるかを必ず確認してから採用してください。
- CT は資産インベントリではありません。 CT は証明書のリクエスト記録です。内部 CA、自己署名証明書、オリジン証明書を使うホストや、HTTP のみのホストは含まれません。CT から得た一覧を完全なものとして報告してはいけません。
- ホストがなくなっても名前は残ります。 CT に記録された過去の名前のほとんどは、すでに使われていません。解決できないサブドメインが400件ある一覧は、未検証の主張が400件あるということです。
- 所有者が変わっても名前は残ります。 ドメインが以前の所有者のものだったときにホスト名に対して発行された証明書は、現在の所有者について検索しても表示されます。
who-owns-this-domainを使ってドメインの登録・移転履歴を確認し、not_beforeと照合してください。 - CNAME でつながった第三者は、対象の資産ではありません。 対象が所有するホスト名が SaaS テナントを指している場合、それは対象のインフラストラクチャではなく、対象と SaaS の関係性です。ベンダーの露出を対象の露出として扱わないでください。
- 集約サービスの結果は、通知もなく食い違います。 ツールごとに異なるソースを検索しており、無料プランでは通知なしに結果が途中で打ち切られることがあります。2つのツールが同じ50件の名前を返しても、どちらも同じ1つのソースを参照している可能性があります。
- 意図的な汚染。 対象のものに見えるドメイン上で、自分が管理する名前の証明書を取得することを、誰も阻止できません。タイポスクワッティングされた名前が、CT 検索では対象自身のホストのように表示されることがあります。登録可能ドメインを1文字ずつ確認してください。
確信度の評価
- 確認済みの資産 — 名前が解決され、登録を確認済みのドメイン配下にあり、対象の他のホストと一貫性のあるインフラストラクチャ(同じ ASN、同じ証明書発行者、同じ命名規則)上にあります。
- 可能性が高い資産 — 確認済みの対象ドメイン配下にある CT 上の名前で、現在は解決されないもの、またはベンダーの共有プラットフォームに解決される名前です。名前の実在は確認できていますが、現在の状態は未確認です。
- 未確認 — 無関係な顧客とバンドルされた証明書に記載された名前、ワイルドカード DNS ゾーンでのブルートフォースによる検出結果、裏付けとなるリンクのない別の登録可能ドメイン上の名前、または基となる証明書や DNS の回答を確認していない集約サービスの結果です。
ホストごとに、名前の出所、証明書の id またはパッシブ DNS のソース、not_before の日付、タイムスタンプ付きの名前解決結果を記録してください。
実例
対象:example-health.test。スコープはパッシブのみです。
crt.sh で %25.example-health.test を検索すると、重複を除いて61件の名前が返されます。プレ証明書と証明書のペアを重複排除すると、38件になります。そのうち、すぐに注目すべき名前が3つあります。
vpn-uat.example-health.test、jira.internal.example-health.test、billing-legacy.example-health.test です。
ある証明書には、無関係な9社にわたる44件の名前が記載されていました。マネージドホスティングプロバイダーのバンドルです。対象以外の43件は除外します。それが行き止まりであり、除外しなければ実際の調査結果よりもレポートが大幅に膨らんでいたでしょう。
38件を名前解決すると、12件から回答がありました。jira.internal は公開 DNS では解決されませんが、証明書に記載されていることから、内部の命名規則と Jira インスタンスの存在が確認できます。確認可能なホストはありませんが、記録する価値があります。vpn-uat はアプライアンスベンダーのネットブロックに解決され、find-exposed-servers で調査できます。
証明書の1つに記載された組織名でアイデンティティ検索を行うと、examplehealth-group.test の証明書が2件見つかりました。このドメインについては、調査概要書に記載がありませんでした。who-owns-this-domain を使った WHOIS の確認では、同じ登録者組織が示されました。これが調査範囲を拡大するきっかけになりました。
評価:解決されるホスト12件は確認済み、jira.internal は可能性が高い(名前の実在は確認済み、公開アクセス不可)、関連ドメインは法人登記書類で確認できるまでは可能性が高いです。
ピボット
| 新しいセレクター | 移動先 |
|---|---|
| 稼働中のホスト名とその IP | find-exposed-servers |
| 関連ドメインおよび買収したドメイン | who-owns-this-domain、who-really-owns-it |
| 証明書のサブジェクトから組織名を特定 | x-ray-a-company |
| 過去のコンテンツが残る廃止済みホスト名 | read-deleted-pages |
| 開発/ステージング用のホスト名、リポジトリらしき名前 | secrets-in-git-history |
| 新たに見つかったホスト上のインデックス済みファイル | google-like-a-spy |
| 構造化する必要がある大量のホスト/ドメイン/IP のセット | graph-the-network |
法律および ToS に関する注意事項
CT ログとパッシブ DNS の読み取りは、公開を前提とした仕組みです。データは読み取り可能な状態で存在しています。実際に考慮すべき制限は 2 つあります。1 つ目は、crt.sh のような無料サービスは共有インフラであるため、自動クエリを大量に行うとアクセスをブロックされ、他の利用者にも迷惑がかかることです。クエリの範囲を限定し、結果をキャッシュしてください。2 つ目は、DNS のブルートフォースや HTTP プロービングは対象にトラフィックを送信するため、量や管轄区域によっては無許可の活動と見なされる可能性があることです。../../ETHICS.md に従い、書面で許可された範囲内で実施してください。ダングリング CNAME や公開状態のステージングホストを発見した場合は、テストするのではなく、報告する必要があります。