hunt-schema-enumeration について
API のセキュリティテスト担当者向けのブラックボックス型スキーマ列挙スキルです。構造化エラーやクエリ応答からテーブル名、フィールド名、エンドポイントを探り、PostgREST、入力検証エラー、GraphQL の確認方法と限界を説明します。
主な機能
- 01PostgREST のヒントからテーブル名を発見
- 02入力検証エラーからフィールド情報を抽出
- 03GraphQL のイントロスペクションクエリ
- 04ワードリストによるテーブル名のファジング
- 05結果の確認と誤検知の判別
活用シーン
- 01PostgREST API が公開するテーブルの把握
- 02エンドポイントのエラーから必須フィールドを確認
- 03イントロスペクション制限時に GraphQL の型情報を調査
- 04許可された書き込みテストの対象エンドポイントを特定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-schema-enumerationインストール後、Claude Code で/hunt-schema-enumerationを入力して読み込まれたか確認します。
詳細
使用するタイミング
対象の API は、有効なテーブル名、フィールド名、エンドポイントパスの手がかりとなる構造化エラーメッセージ(JSON)を返します。これは REST/GraphQL API に対するブラックボックス調査で最も成果の高い手法です。ファジングリクエストを 1 回送るだけで、データベーススキーマ全体が明らかになります。
特によく見られるのは、PostgREST(Supabase)、FastAPI(.NET)、Zod(Next.js/Node)、tRPC、GraphQL、および検証エラーの詳細を本番環境で有効にしているあらゆるフレームワークです。
フェーズ 1 — PostgREST エラーヒントの列挙
PostgREST は Supabase/PostgreSQL 用の REST API レイヤーです。存在しないテーブルをクエリすると、実際のテーブル名を含むヒントが返されます。
SUPABASE_URL="https://PROJECT.supabase.co"
ANON_KEY="eyJ..."
# Fuzz with common table names — read the hints
for table in users profiles posts products orders data config settings; do
echo "=== $table ==="
curl --max-time 30 --connect-timeout 10 -sk "${SUPABASE_URL}/rest/v1/${table}?select=*&limit=1" \
-H "apikey: ${ANON_KEY}" \
-H "Authorization: Bearer ${ANON_KEY}" 2>/dev/null | python3 -c "
import sys,json
d=json.load(sys.stdin)
hint=d.get('hint','')
if hint: print(f' -> {hint}')
"
done
# The response pattern:
# {"hint":"Perhaps you meant the table 'public.real_table_name'"}
# {"hint":"Perhaps you meant the table 'public.user_sessions'"}
標的型ファジング用のワードリストを作成する:
# Common patterns found in field:
# - Game apps: hands, scores, sessions, players, items, inventory
# - SaaS: subscriptions, subscribers, billing, invoices, teams, api_keys
# - Health: patients, appointments, assessments, prescriptions
# - Gov: citizens, certificates, documents, protocols
# - Finance: transactions, accounts, wallets, withdrawals, deposits
フェーズ 2 — Zod/FastAPI の検証エラーの調査
最新のフレームワークは、想定されるすべてのフィールドを明らかにする詳細な検証エラーを返します。
FastAPI(.NET/Go)
# POST with empty body or wrong fields
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://api.target.com/endpoint" \
-H "Content-Type: application/json" -d '{}' 2>/dev/null
# Response reveals ALL required fields:
# {"errors":{"usuario":["required"],"senha":["required"]}}
Zod(Next.js/Node)
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/workspaces" \
-H "Content-Type: application/json" -d '{}' 2>/dev/null
# Response: {"error":{"name":"ZodError","message":"[\n {\"expected\":\"string\",\"path\":[\"name\"]}\n]"}}
フェーズ 3 — GraphQL イントロスペクション
# Standard introspection query
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"{__schema{types{name fields{name type{name}}}}}"}' 2>/dev/null
# Even if introspection is disabled, error messages reveal type names:
# "Cannot query field 'x' on type 'User'. Did you mean 'users'?"
フェーズ 4 — 積極的なテーブルファジング
以下を組み合わせて包括的なワードリストを生成します:
# 1. From JS bundle analysis
grep -Eo 'from\(["\x60][a-zA-Z_]+["\x60]\)' /tmp/target.js | sort -u
# 2. From common patterns
# Singular/plural: user/users, post/posts, product/products
# Snake/camel: user_sessions, userSessions, UserSessions
# Domain-specific: appointments, patients, assessments, certificates
# 3. Systematic fuzz
for table in $(cat /tmp/wordlist.txt); do
curl --max-time 30 --connect-timeout 10 -sk -w "%{http_code}" "${BASE}/rest/v1/${table}?select=count" \
-H "apikey: ${KEY}" 2>/dev/null | tee -a /tmp/fuzz_results.txt
done
検証
- PostgREST のヒットを確認:レスポンスが
[](空の配列 = テーブルは存在するが、RLS によって読み取りがブロックされている)またはデータが返される - Zod のヒットを確認:エラーに、想定される正確なフィールド名と型が列挙されている
- FastAPI のヒットを確認:
detail配列に不足しているフィールドが列挙された 422 - 誤検出:一般的な 404 HTML ページ(JSON エラーではない)
次にすること
- PostgREST のヒントでテーブルが明らかになった場合 →
hunt-write-gapに進む(PATCH/POST/DELETE をテスト) - Zod のエラーでフィールドが明らかになった場合 →
hunt-business-logicをテストする(マスアサインメント、価格の改ざん) - FastAPI で認証スキーマが明らかになった場合 →
jwt-attackまたはapi-noauth-huntをテストする - スキーマの列挙は常に次の攻撃につながります。最終ステップではありません
検証
このセルフテストを実行し、スキーマ列挙調査の準備が整っていることを確認します:
-
スキルの整合性 — スキルファイルが読み取り可能で、形式が正しいことを確認します:
grep -q "name: hunt-schema-enumeration" SKILL.md && echo "PASS: skill frontmatter present" || echo "FAIL" grep -q "revision_date:" SKILL.md && echo "PASS: revision date present" || echo "FAIL" -
カテゴリの確認 — スキルにカテゴリがあることを確認します:
grep -q "category:" SKILL.md && echo "PASS: category present" || echo "FAIL" -
落とし穴のセクション — 落とし穴が記載されていることを確認します:
grep -q "^## Pitfalls" SKILL.md && echo "PASS: pitfalls section present" || echo "FAIL"
3 つのテストすべてにより、スキルが適切に構成され、使用する準備が整っていることを確認できます。
落とし穴
- 機密フィールドを伴わないスキーマ列挙 — API スキーマを把握することは調査です。悪用可能なフィールドや変更操作を実証する必要があります。
- イントロスペクションによる GraphQL スキーマの取得 — イントロスペクションは機能であり、バグではありません(本番環境で明示的に無効化されている場合を除く)。
- エラーメッセージによるデータベーススキーマの開示 — テーブル名が明らかになる SQL エラーは情報開示であり、スキーマ固有の問題ではありません。開示された内容に基づいて評価します。
- OpenAPI 仕様が一般公開されている —
/swagger.jsonまたは/openapi.jsonは、API 利用者向けに意図的に公開されています。公開されている管理用/内部エンドポイントに基づいて評価します。