PR 本記事には広告(Amazonアソシエイト・もしもアフィリエイト・A8.net等)が含まれます。掲載情報の正確性には努めていますが、商品の詳細は必ずリンク先で最新情報をご確認ください。
CTF・セキュリティ学習

【ディレクトリ列挙編】リンクされてない隠しエンドポイントを掘る|CTF思考フレームワーク R04

かも次郎とアンペンが「ディレクトリ列挙」を解説するマスコットイラスト
安全に生きたい編集部

こんにちは、アンペンです!偵察ルートR04はディレクトリ列挙編。トップページからリンクをたどっても出てこない『隠しエンドポイント』を、辞書を使った総当たりで掘り出す技を扱います。指紋(R03)で当たりを付けたサーバの内部構造を、さらに一段深く読む回です。

Webサイトには、トップページからリンクをたどっても絶対にたどり着けない“裏ページ”が、実はたくさん眠っています。開発中の管理画面、消し忘れたバックアップ、テスト用のAPI——表に出していないだけで、サーバの上にはちゃんと置いてある。リンクが無いから安全、と思いがちですが、URLを直接叩けば応答してしまうんです。今日は、その“隠し扉”を辞書で炙り出す技と、その塞ぎ方を見ていきましょう。

リンクが無いページって、どうやって見つけるの?

『ありそうな名前』を辞書で総当たりするんだ。/admin /backup.zip /.git/…候補を片っ端から投げて、サーバの反応の差から実在を当てる。ffufやgobusterが定番だよ。

まず結論

ディレクトリ列挙(Content Discovery)とは、リンクされていない隠しパスをワードリストで総当たりし、HTTPステータスコードの差から実在を炙り出す偵察。鍵は(1)良いワードリスト(SecLists)、(2)ステータスの読み分け(200/301/403が宝)、(3)拡張子総当たり(.bak/.zip/.old)、(4)見つけた階層の再帰探索の4点。とくに403(あるのに拒否)は「隠したい何かがそこにある」サインで最優先。代表ツールはffufgobusterferoxbuster。守る側の鉄則は『不要ファイルを公開領域に置かない+ディレクトリ一覧無効化+大量404をログ検知』

この記事で分かること

  • ディレクトリ列挙が「リンクなし」でも成立する仕組み
  • ステータスコードの読み分け(なぜ403が一番おいしいのか)
  • ffuf/gobuster/feroxbufferの役割分担とワードリスト選び
  • 拡張子総当たり・再帰探索・.git/.envの定番事故
  • 守る側の「隠しパスを漏らさない」チェックリスト
難易度:初〜中級 所要時間:11分 体験:自分のサイトで列挙 おすすめ:R03の後

📖 はじめてのWebセキュリティR04|ディレクトリ列挙編
リンクされていない隠しエンドポイントを掘り出す偵察の作法。 シリーズ一覧を見る →

⚠️ 大事なお約束
他者サイトへのディレクトリ列挙は、たとえ閲覧目的でも大量アクセスによる業務妨害・不正アクセスとみなされ違法になり得ます。本記事の手順はCTF・自分が運用するサイト・書面で許可された対象でのみ実施してください。

なぜ「リンクなし」でも見つかるのか

Webサイトのページは、トップから辿れるリンクの集合(=サイトマップ)だけではありません。開発中の管理画面、消し忘れたバックアップ、設定ファイル、テスト用APIなど、「公開する気はないがサーバ上には置いてある」ファイルが大量にあります。これらはリンクされていないので普通には見えませんが、URLを直接叩けば応答します。ディレクトリ列挙は、その「ありそうな名前」を機械的に総当たりして実在を当てる手法です。

判定の生命線がHTTPステータスコードです。存在しなければ404、あれば200、移動なら301/302、認証が要れば401、そして「あるけど見せない」が403。この差を読み分けることで、画面を一切見なくても「そこに何があるか」の地図が描けます。

ここで効いてくるのが“サーバの表情”です。人は嘘をついても表情に出ますよね。サーバも同じで、存在しないパスには『404(ありません)』、あるけど見せたくないものには『403(立入禁止)』と、つい違う反応を返してしまう。攻撃者はこの“表情の差”だけを頼りに、中身を一切見ずに『どこに何があるか』を当てていきます。とくに403は、本人が隠したがっている証拠なので、いちばん注目されるわけです。

ワードリストでFUZZ総当たりしHTTPステータス200/301/403/404で篩い分ける列挙フロー図
図1:ワードリスト総当たり→ステータスの差で隠しパスを地図化

ここで覚える用語:ファジング(Fuzzing)とワードリスト
意味:ファジングとは、大量の候補を機械的に投げてサーバ応答の差から「当たり」を炙り出す汎用手法。FUZZというキーワードを置いた位置に、ワードリスト(辞書ファイル)の各行を順に当てはめて試します。
例:ffuf -u https://site/FUZZ -w wordlist.txt なら、/admin /login /backup…を上から順に試行。
使いどころ:ディレクトリ・ファイル名・URLパラメータ・サブドメインなど「総当たりで列挙したい全て」に応用できます。定番辞書はSecListsraft-*directory-list-2.3

ステータスコードの読み分け(403が宝)

  • 200 OK:そのパスは実在し、中身も見られる。最優先で内容確認
  • 301/302 リダイレクト:移動先がある=存在の証拠/admin/admin/のような誘導も拾う
  • 403 Forbidden:「あるのに見せない」=隠したい何かがそこにあるサイン。最もおいしい。別経路・別メソッド・パストラバーサルで回り込めないか検討
  • 401 Unauthorized:認証が必要=重要機能の入口。資格情報やデフォルトパスを検討
  • 404 Not Found:無し。ただし「全部200を返すソフト404」に注意(後述のフィルタが必要)
  • 500 Internal Server Error:叩いた瞬間に落ちる=処理が走っている証拠。パラメータ次第で脆弱性の入口

図解:列挙からお宝発見までの流れ

ワードリスト投入→ステータスで篩(ふるい)分け→200/301/403を深掘り→拡張子総当たり→見つけた階層を再帰探索、という流れで内部構造の地図が完成します。

🏨 たとえるなら、ホテルの廊下でドアノブを回す

ホテルの案内図には客室番号しか載っていませんが、廊下には「清掃用具室」「電気室」「関係者通路」といった案内外のドアがいくつもあります。案内図(=リンク)を見るだけでは気づきませんが、廊下を歩いてドアノブを片っ端から回せば「ここは施錠されていない(200)」「ここは『関係者以外立入禁止』の札がある(403)」と分かってしまう。ディレクトリ列挙はまさにこれで、札がかかっているドアほど『中に大事なものがある』と教えてくれるのです。

案内図に載らないドアのノブを回して施錠状況や立入禁止札を確かめるホテル廊下のたとえイラスト
図2:札のかかったドアほど中身が大事=ディレクトリ列挙

ツールの役割分担とコツ

  • ffuf:高速・柔軟。FUZZ位置を自由に置けるのでパラメータやHost列挙にも転用可。フィルタ(-fc/-fs/-fw)が強力
  • gobuster:シンプルで堅牢。dir(ディレクトリ)/dns(サブドメイン)/vhostモードを持つ
  • feroxbuster:自動再帰探索が得意。見つけたディレクトリの奥を勝手に掘り進む
  • dirsearch:拡張子総当たりとレポート整形が手軽。初学者に優しい

ツールはどれも似ていますが、ざっくり『ffufは万能でフィルタが強い、feroxbusterは奥まで勝手に掘ってくれる、gobuster/dirsearchは手軽』と覚えておけば十分です。最初の1本はffufかdirsearchで始め、ディレクトリがいくつか見つかったらferoxbusterで再帰探索に切り替える——この流れが効率的。道具より大事なのは“良い辞書”なので、まずSecListsを用意するのが先決ですよ。

ここで覚える用語:ソフト404とフィルタリング
意味:「存在しないパスにも200と独自エラーページを返す」設定をソフト404と呼びます。これがあると全部が当たりに見えて列挙が機能しません。そこで応答サイズ・行数・単語数でフィルタします。
例:存在しないパスが常に4242バイトなら ffuf ... -fs 4242 でそのサイズを除外。
使いどころ:列挙の最初に「絶対に無いパス(例:/zzz_notexist_123)」を1回叩いて基準サイズを測り、それを-fs/-fwに渡すのが定石です。

CTFでやってみよう:自サイトを列挙する

やってみよう / 自分の環境・CTFのみ

自分が運用するサイトの「隠し扉」を自分で点検する

攻撃者が最初の数分でやる列挙を、自分のサイトに対して先に実行して棚卸しします。各ステップに「なぜやるか」を添えました。

  1. SecListsからraft-medium-directories.txtを用意 → なぜ:実績ある辞書が精度と速度を両立するから
  2. 基準測定:curl -s -o /dev/null -w "%{size_download}" https://yoursite/zzz_notexistなぜ:ソフト404のサイズを掴みフィルタに使うため
  3. ffuf -u https://yoursite/FUZZ -w 辞書 -mc 200,301,302,401,403 -fs 基準値なぜ:意味あるステータスだけ拾い偽陽性を消すため
  4. 拡張子総当たり -e .php,.bak,.zip,.old,.txt,.jsonなぜ:消し忘れたバックアップ/設定が最大の宝庫だから
  5. 見つかったディレクトリをferoxbusterで再帰探索 → なぜ:階層の奥に本命(管理API等)があるから
  6. /.git/ /.env /backup.zip /config.php.bakを個別確認 → なぜ:最頻出の情報漏えい事故だから
  7. -rate-tでレート制御し、サーバのアクセスログを観察 → なぜ:本番では過負荷・検知になるので加減を体感するため
  8. 検出した403/401を重点的に記録なぜ:「存在するのに隠したい」=価値が高いから
他者サイトへの列挙は禁止。大量リクエストは業務妨害になり得ます。検証は必ず自分のサイト・CTFのみで。

守る側:隠しパスを漏らさない

守る発想は「置かない・出さない・気づく」。そもそも公開領域に余計なファイルを置かず、構造を出さず、列挙の兆候に気づく。具体策を並べます。

隠しパスを漏らさないチェックリスト
  • ディレクトリ一覧の無効化:Apache Options -Indexes/Nginx autoindex off;
  • .git/.svn/.env を公開領域に置かない+アクセス拒否ルール(漏れれば全ソース流出)
  • バックアップ/一時ファイル排除:.bak .old ~ .zip .swpをWebルートから除去
  • 存在を隠すなら一律404:403で「ある」と教えず、秘匿対象は404相当で返す
  • WAF/レート制限:同一IPの短時間大量404/403をブロック
  • 管理画面はパス秘匿に頼らない:認証+IP制限+多要素を必須に
  • ログ監視+アラート:大量404/403はディレクトリ列挙の典型サイン
  • robots.txtに秘密パスを書かない:かえって地図を渡すことになる
ディレクトリ一覧OFF・git/env非公開・バックアップ排除・一律404・ログ検知の守り側チェックリスト図
図3:隠しパスを漏らさない守り側チェックポイント

403を返すと逆に「ある」ってバレるのか…!

そう、存在を隠したいなら『無いふり(404)』が正解。次はR05、Google Dork。一度もサイトを叩かずに、検索エンジン経由で隠しファイルを見つける受動偵察だよ。

まとめ:『辞書×ステータス×再帰』

今回のポイント
  • 列挙はワードリスト総当たり×ステータスの読み分けで成立する
  • 403/401は宝(あるのに隠したい=価値が高い)
  • ソフト404はサイズ/語数フィルタで除外する
  • 拡張子総当たりと再帰探索でバックアップ・奥の階層を掘る
  • 守りは置かない・出さない(一律404)・気づく(ログ検知)

今日の持ち帰りは『403は“隠す”どころか“ここにあるよ”の看板』。存在を伏せたいなら、中途半端に拒否するより、いっそ“無いふり(404)”をするのが正解です。そして根本は、見られて困るものを公開領域に置かないこと。.gitやバックアップzipの置き忘れは、今もっとも多い情報漏えい事故。攻撃者と同じ辞書で、一度自分のサイトを叩いてみてください。

次はR05、Google Dork編。サーバを一切叩かずに検索エンジン経由で隠し情報を拾う、究極の受動偵察を扱います。

次に読みたい記事

参考資料

記事URLをコピーしました