Shikata Ga Nai

Private? There is no such things.

Lab: Username enumeration via different responses — 解説と手順(APPRENTICE)

Hello there, ('ω')ノ

概要(この文書で何を学べるか)

このラボでは、ログイン機能の エラーメッセージの違い から、 存在するユーザ名だけ異なる応答を返してしまう脆弱性(username enumeration) を悪用して、

  1. 有効なユーザ名の特定(列挙)
  2. そのユーザ名に対するパスワード総当たり(brute force)
  3. 正しい認証情報でログインしアカウントページに到達

という一連の攻撃手法を学びます。

Burp Suite の Intruder(Sniper 攻撃) を活用して、レスポンスの 長さメッセージ内容 の違いから正解を特定する構成になっています。


前提知識

  • エラーメッセージの違い=情報漏洩 → 「Invalid username」と「Incorrect password」が異なる例が典型的。
  • ブルートフォースの基本操作 → まずユーザ名の列挙、次にパスワードを試す。
  • Burp Intruder(Sniper 攻撃)の仕組み → 指定したパラメータだけを一つずつ変えながら総当たりする。

なぜこの順序で進めるのか(考え方)

  1. ユーザ名だけ先に当てるのがもっとも効率的 パスワードの総当たりは非常に時間がかかるため、まず有効なユーザ名を 1 つだけ特定するのが合理的です。

  2. レスポンスの違いは強力な手がかり 多くのアプリは「存在しないユーザ」と「存在するがパスワードが違う場合」で 微妙に異なるレスポンス を返します。 この差異(本文の長さ・内容・ステータスコード)を Intruder が一覧表示してくれるので比較できます。

  3. ユーザ名がわかればパスワードの特定は容易 正しい組み合わせだけ 302(リダイレクト)など、挙動が明確に変化するため判定が簡単です。


実際の手順(1 アクションごとに「なぜ」を解説)

以降の操作は必ずラボ環境でのみ行ってください。


ステップ 1 — ログインフォームに適当な値を入力し Burp で捕まえる

  1. ブラウザでラボのログイン画面を開く
  2. 適当なユーザ名(例:aaa)とパスワード(例:bbb)でログインを試す
  3. Burp Suite → Proxy > HTTP historyPOST /login が記録される

なぜ? → 後で Intruder に送るため、「実際にログイン時に飛ぶリクエスト」を手に入れる必要があるからです。


ステップ 2 — Intruder に送って “ユーザ名列挙フェーズ” の準備

  1. POST /login を右クリック → Send to Intruder
  2. Intruder(Positions)を開くと、username=§invalid§ のように自動的に username 部分が §で囲まれる
  3. attack type が Sniper であることを確認
  4. パスワード部分は固定値のままで OK
  5. Payloads タブへ移動し、Payload type を Simple list にし、 candidate usernames を貼り付ける
  6. Start attack

なぜ? → Sniper攻撃では「1 箇所だけ変える」という操作が自動化されるため、ユーザ名だけを試すのに最適です。


ステップ 3 — Length 列の違いから 有効なユーザ名 を特定

Attack のウィンドウで結果を見る。

  1. Length 列をクリックしてソート
  2. ほとんどのレスポンスの Length は同じ
  3. 1 つだけ Length が違うエントリ がある
  4. そのレスポンスを確認すると

    • 他のエントリ:Invalid username
    • このエントリ:Incorrect password
  5. このレスポンスの Payload(ユーザ名)が “実在ユーザ”

なぜこれでわかる? → アプリが

  • ユーザが存在しない場合 → Invalid username
  • ユーザは存在するがパスワードが違う場合 → Incorrect password という 異なる応答 を返してしまっているからです。 これが脆弱性そのものです。

ステップ 4 — Intruder を再設定して “パスワード総当たりフェーズ” へ

  1. Intruder → Positions に戻る
  2. Clear § を押してすべて削除
  3. username をさきほど特定した「有効ユーザ名」に固定
  4. password の値を §xxx§ で囲んでペイロード位置にする
   username=valid-user&password=§invalid-password§
  1. Payloads に candidate passwords を貼り付ける
  2. Start attack

なぜ? → 今度は「パスワードだけ変える」必要があるため、username は固定し password を Sniper の対象にします。


ステップ 5 — Status 列から 正しいパスワード を特定

Attack のウィンドウで結果を確認。

  1. Status 列 を見比べる
  2. 大半は 200 OK(ログイン失敗)
  3. 1 つだけ 302(リダイレクト)など挙動が異なるものがある
  4. このエントリの Payload に表示されている password が 正解

なぜ 302 なのか? → ログイン成功した場合、アプリは「アカウントページ」へリダイレクトするため Status が変化するためです。


ステップ 6 — 正しい認証情報でログインしてラボクリア

  1. 得られた

    • 正しいユーザ名
    • 正しいパスワード をログインフォームに入力
  2. My account ページに到達
  3. ラボが Solved 状態になる

よくある失敗と対処法

症状 原因・対処
Length が全部同じ 本文の差異(メッセージ内容)を比較する。HTMLコメントや位置の微妙な違いがヒントの場合もある。
302 が出ない Cookie が切れている/セッションが必要。Intruder の request headers を確認。
エラーが全部同じ 正しい Payload list を貼っていない可能性。ラボが提供する Candidate usernames / passwords を使う。
Intruder が遅い Burp の resource pool 制限。低速になるが結果には影響なし。

セキュリティ的な学び(なぜ危険か)

  • エラーメッセージの差異は情報漏洩の原因となる
  • 正しいユーザ名さえ分かればパスワード総当たりが容易になる
  • 認証周りは常に “同じエラーメッセージ・同じレスポンス時間” が必須

実務では次の対策が必須:

  • ユーザ名とパスワードどちらが間違っていても同じエラーを返す
  • レート制限(Rate Limit)・アカウントロック・CAPTCHA の導入
  • ログイン試行を監視・警告

まとめ(ワンフレーズ)

レスポンスの違いから実在ユーザを特定し、そのユーザに対してパスワード総当たりを行い、正しい組み合わせでログインしてラボをクリアする。

Best regards, (^^ゞ