关于 hunt-business-logic
hunt-business-logic 是面向漏洞赏金测试者的安全测试技能,用于检查交易、验证和访问控制流程中的缺陷。内容围绕业务影响,整理攻击面线索、测试步骤、绕过模式和影响验证。
主要功能
- 01交易与验证流程检查
- 02速率限制与请求头篡改测试
- 03支付与 Webhook 校验检查
- 04内部页面发现
- 05影响验证清单
适用场景
- 01测试结账价格是否可被篡改
- 02检查 API 是否执行验证门槛
- 03评估回调与 Webhook 的防护
- 04查找暴露的内部页面
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-business-logic安装后在 Claude Code 中输入/hunt-business-logic确认已加载。
详细介绍
高价值目标
在金融交易、身份验证和访问控制与现实后果交汇的平台中,业务逻辑漏洞的收益最高。最有价值的目标包括:
- 电商与支付平台(Valve/Steam、Shopify)——操纵支付流程、免费获取商品、篡改价格
- 市场平台与零工经济应用(Airbnb、Uber)——绕过身份验证,进而实施欺诈或引发不安全互动
- 采用分级访问权限的 SaaS(Mozilla Monitor)——绕过验证,在无权限的情况下解锁监控功能
- 高流量消费类应用(Snapchat、Yelp)——绕过速率限制,从而大规模发送垃圾信息、枚举数据或实施滥用
高收益资产类型:结账流程、订阅端点、回调/验证系统、Webhook 处理程序、暴露在互联网上的员工/内部门户,以及任何信任客户端提供的数据来做出授权决策的端点。
攻击面信号
需要关注的 URL 模式:
/checkout、/order、/subscribe、/payment、/verify、/confirm、/callback/internal、/employee、/summit、/staff、/admin——意外公开的内部页面/api/v*/payment、/api/v*/notify、/webhook——支付服务提供商的回调- 接受
X-Forwarded-For、X-Real-IP、CF-Connecting-IP标头的端点
响应/标头信号:
Set-Cookie中包含未经验证、与购物车或订单数据关联的会话状态- 响应中出现支付服务提供商名称:
Smart2Pay、Stripe、PayPal、Braintree - 经由第三方支付页面的重定向链(可在传输过程中获取数据)
- 订阅/验证端点返回
200 OK,且没有 CAPTCHA 或令牌
JS 模式:
- 前端捆绑文件中硬编码的内部 URL(
/employee/、/staff/、/internal/) - 提交到服务器前在客户端计算价格
- 仅在前端检查的验证逻辑(
if (verified) { ... }) fetch('/api/subscribe', { method: 'POST', body: ... }),且没有防 CSRF 令牌或速率限制令牌
技术栈信号:
- 带有草稿/未发布渠道页面的 Shopify 店面
- 使用基于 IP 的速率限制、但未绑定会话/账户的应用
- 未验证 HMAC 签名的支付 Webhook
- 启用功能前未验证所有权的短信/电话回调流程
逐步狩猎方法
-
梳理所有身份验证边界。 对目标进行爬取。找出提供已验证身份用户内容的页面/端点(员工门户、高级功能、订单页面),并逐一测试未通过身份验证时的情况。查找 JS 包中索引到的内部页面,或
robots.txt/sitemap.xml中链接的页面。 -
找出所有验证流程。 列出:电子邮件验证、电话/SMS 验证、付款验证、CAPTCHA、年龄门槛。对每种流程进行测试:如果完全跳过验证步骤会发生什么?如果在其他账户上重放有效令牌会发生什么?
-
测试每个表单上的速率限制控制。 对每个 POST 端点(订阅、登录、OTP、搜索)快速发送 50+ 个请求。尝试不同方式:移除 Cookie、轮换
X-Forwarded-For/X-Real-IP标头、更改User-Agent。检查服务器是否使用标头中的 IP,而非连接 IP。 -
拦截并篡改付款流程。 使用 Burp Suite 拦截浏览器、应用程序和付款提供商之间的每个请求。找出价格、货币、订单 ID 或状态字段的设置位置。尝试将金额改为 $0.01,或将货币改为低价值货币。查找接受付款确认的 POST 回调/webhook 端点,并测试它们是否验证 HMAC/签名。
-
测试电话/回拨号码验证。 每当平台接受回拨号码时,测试:能否将号码设置为自己不拥有的号码?平台会不会呼叫/短信该号码,并仅凭提交号码就授予信任?试着将其设为受害者的号码。
-
检查未受保护的员工/内部界面。 在 Shodan、GitHub、JS 包和 Wayback Machine 中搜索内部子域名/路径引用。测试未经身份验证能否访问。检查这些界面是否允许下单、访问数据或提升权限。
-
评估业务影响。 对每项发现,判断是否会造成经济损失、未授权访问或数据泄露。记录完整攻击链。
攻击载荷与检测模式
通过轮换标头绕过速率限制:
# Rotate X-Forwarded-For to bypass IP rate limiting
for i in $(seq 1 100); do
curl --max-time 30 --connect-timeout 10 -s -X POST https://target.com/api/subscribe \
-H "X-Forwarded-For: 10.0.0.$i" \
-H "X-Real-IP: 10.0.0.$i" \
-H "Content-Type: application/json" \
-d '{"email":"victim+'"$i"'@example.com"}' \
-o /dev/null -w "%{http_code}\n"
done
篡改付款——修改传输中的价格:
POST /payment/initiate HTTP/1.1
Host: target.com
amount=0.01¤cy=USD&order_id=12345&product_id=99
# Look for unvalidated webhook endpoints
curl --max-time 30 --connect-timeout 10 -X POST https://target.com/payment/callback \
-H "Content-Type: application/json" \
-d '{"status":"success","amount":"0.01","order_id":"12345","transaction_id":"fake-txn"}'
发现未经身份验证的内部页面:
# Check robots.txt and sitemap for internal paths
curl --max-time 30 --connect-timeout 10 -s https://target.com/robots.txt | grep -iE "(disallow|allow)"
curl --max-time 30 --connect-timeout 10 -s https://target.com/sitemap.xml | grep -iE "(employee|internal|staff|summit|admin)"
# Grep JS bundles for internal paths
curl --max-time 30 --connect-timeout 10 -s https://target.com/assets/app.js | grep -oE '"/[a-zA-Z0-9/_-]{3,50}"' | sort -u
绕过电子邮件验证:
# Skip the verification step: hit the post-verification API endpoint directly
# with an unverified session. If it succeeds, the gate is UI-only.
curl --max-time 30 --connect-timeout 10 -s -X POST https://monitor.target.com/api/monitoring/enable \
-H "Cookie: session=<your_unverified_session>" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}'
# Replay verification token on different account
curl --max-time 30 --connect-timeout 10 -X POST https://target.com/verify \
-d 'token=VALID_TOKEN_FROM_ACCOUNT_A&[email protected]'
用于查找客户端逻辑问题的 grep 模式:
# Find price calculations in JS
grep -iE "(price|amount|total|cost)\s*[=*+]" app.js
# Find internal URLs in JS bundles
grep -oE '"/(employee|internal|staff|admin|summit)[^"]*"' *.js
# Find unvalidated IP header usage in server code
grep -iE "x-forwarded-for|x-real-ip|cf-connecting-ip" src/ -r
常见根本原因
-
服务器信任客户端提供的财务决策数据。 开发者将价格计算交给前端,或通过表单/URL 传递金额字段,却不在服务器上根据规范数据源(产品数据库)重新验证。
-
验证只在 UI 中强制执行,而未在 API 中强制执行。 前端将功能隐藏在验证门槛之后,但后端 API 端点无需验证状态即可正常运行——任何已通过身份验证的请求都能成功。
-
基于 IP 的速率限制读取可伪造的标头。 开发者使用
request.headers['X-Forwarded-For']而非实际连接 IP 来实现速率限制,因此可以通过篡改标头轻易绕过。 -
付款 webhook 缺少签名验证。 开发者实现了“成功” webhook,却未验证付款提供商提供的 HMAC 签名,因此任何人都可以 POST 伪造的成功通知。
-
内部/员工页面没有访问控制。 内部工具部署在生产域名上,却没有身份验证中间件;原因可能是开发者误以为只要 URL 不公开就安全,也可能是忘了给新路由添加身份验证。
-
电话/回拨验证仅供参考,并未强制执行。 系统接受电话号码,并向提交号码的人授予信任,却不确认提交者是否拥有或控制该号码。
-
草稿/特定渠道的店面继承了完整的订单功能。 Shopify 等平台允许为特定渠道(员工活动)创建未公开的店面;只要知道 URL,仍可完整地下单。
绕过技术
| 防御措施 | 绕过方法 |
|---|---|
| 基于 IP 的速率限制 | 每次请求轮换 X-Forwarded-For、X-Real-IP、True-Client-IP、CF-Connecting-IP 标头 |
| 订阅表单上的 CAPTCHA | 优先尝试基于标头的绕过;如果 CAPTCHA 只出现在网页表单上,直接调用底层 API 端点 |
| 邮箱验证关卡 | 直接访问验证后的 API 端点;重放有效令牌;检查 verified=true 是否是由客户端设置的 Cookie/参数 |
| 服务端验证付款金额 | 将货币改为价值较低的货币;尝试 $0.00 或负数金额;篡改订单 ID 以引用其他商品 |
| Webhook HMAC 验证 | 尝试不带签名标头或使用空签名标头(验证是否实际生效——只有在未强制验证时,篡改后的载荷才会“通过”);重放捕获到的未修改 Webhook,以测试是否缺少幂等性/防重放机制 |
| 内部页面上的身份验证 | 尝试未登录访问;尝试使用低权限账户;尝试路径遍历变体(/employee/../employee/) |
| 电话验证(发送 OTP) | 不经过 OTP 验证就提交他人的号码;检查系统是在提交号码时还是在确认 OTP 后授予信任 |
Gate 0 验证
撰写任何报告前,请回答以下三个问题:
-
攻击者现在能做什么? 请具体说明:“未登录用户可以零成本下单购买实物”或“攻击者可以绕过邮箱验证,在未拥有某个邮箱地址的情况下监控该邮箱”或“攻击者可以向任意地址发送无限量的订阅邮件。”影响描述含糊 = 驳回。
-
受害者会遭受什么损失? 明确具体且可归因的损失:经济损失(免费获得商品、欺诈性付款)、隐私损失(伪造电话号码、未经授权的监控)、服务滥用(通过绕过速率限制发起垃圾邮件活动),或安全性降低(未经验证的身份被信任,可执行敏感操作)。如果损失纯属理论推测,请重新评估严重性。
-
能否在 10 分钟内从头复现? 创建一个新账户(或不使用账户)。按照你记录的步骤操作,并实现相应影响。如果你无法依据所写步骤,在 10 分钟内从头到尾稳定地复现问题,则说明方法尚不完整——提交前请完善。
实际影响示例
场景 1 — 通过暴露的内部店铺免费获取实物商品(类似 Shopify) 某员工峰会页面被部署到公开的 Shopify 店铺,作为向员工免费发放书籍的专用渠道。通过分析 JS bundle 或分享链接即可发现该 URL。匿名用户访问该 URL 后,无需身份验证即可浏览商品并完成结账,实物商品由公司承担运费并寄出。影响:每笔订单都会造成直接经济损失;若未能及时发现,还可能被批量下单。
场景 2 — 通过篡改传输中的数据操纵支付(类似 Valve/Steam) 支付流程通过由客户端控制的参数传递订单金额和货币,然后重定向到第三方支付服务提供商(Smart2Pay)。攻击者可以使用 Burp Suite 拦截重定向并修改金额字段,以 $0.01 完成真实支付;由于应用的 webhook 未进行 HMAC 验证,因此会接受服务提供商的确认,并向账户发放完整的商品/服务。影响:造成严重的经济损失;攻击者几乎无需付费即可获得全部价值的商品/服务,而且可以无限次重复利用。
场景 3 — 绕过电子邮件验证,未经授权地进行监控(类似 Mozilla) 某泄露监控服务要求先验证电子邮件地址,才能为其启用监控提醒。验证检查仅在 UI 流程中执行,但底层 API 使用有效会话即可接受针对任意地址的监控设置请求,完全跳过验证步骤。攻击者可以监控自己并不拥有的电子邮件地址,并接收受害者账户的泄露通知数据(可能包括凭据是否已泄露)。影响:侵犯隐私;攻击者可以在目标不知情或未同意的情况下,获知目标的电子邮件是否出现在数据泄露事件中。
已披露报告引用(补充 +5 — 2016-2023)
以下 5 个真实且经过验证的漏洞赏金/协调披露案例扩展了此技能。这 5 个案例都具有可衡量的财务影响(已证实的实际损失或可量化的平台级风险敞口)。
-
Stripe — 费用折扣竞态重复兑换(H1 #1849626)
- 子类:优惠券/折扣竞态重复兑换 + 财务原语
- 攻击载荷:Stripe 支持团队发放了一次性 $20,000 费用抵扣额度。研究人员捕获了“accept-discount” POST 请求,并通过 Burp Turbo Intruder 并行重放 30 次,每次接受都会再次为账户记入抵扣额度
- 根本原因:折扣接受端点缺少幂等性;(account_id, discount_id) 没有唯一约束
- 年份:2023 — $5,000,修复前累计产生了 $600,000 的免手续费交易(按 3% 抽成计算,Stripe 实际损失约为 $18,000)
-
marketplace.example.com — 礼品卡竞态重复兑换(H1 #759247)
- 子类:礼品卡/商店额度竞态重复兑换
- 攻击载荷:使用一张有效礼品卡,通过 Turbo Intruder 从 10 个套接字并行向
/redeem发送 POST 请求。余额会增加面值的 N 倍 - 根本原因:gift_card 表没有行级锁;余额扣减和入账分别在不同事务中执行
- 年份:2019 — $1,500
-
Upserve / OLO — 负数量价格操纵(H1 #364843)
- 子类:购物车负数量价格篡改
- 攻击载荷:
POST /api/order {"items":[{"id":1,"qty":1,"price":50},{"id":2,"qty":-3,"price":50}]}— 订单总额计算为-$100,在扣款时被限制为约 $0,但食物仍会照常配送 - 根本原因:服务器将
qty * price相乘时未检查qty >= 1 - 年份:2018 — 该子类的典型引用案例(仅获确认的计划)
-
Krisp — 篡改 PUT 请求以降低每席位费用(H1 #1446090)
- 子类:单位价格批量赋值/数量折扣操纵
- 攻击载荷:
PUT /v2/seats请求正文包含一个服务器信任的price字段。将price=1替代 $60。订阅更新后,计费引擎会按每席位 $1 向 100 个席位收费 - 根本原因:服务器从请求正文读取价格,而不是通过 plan_id 查询;这是典型的批量赋值
- 年份:2021 — 使用 Stripe 计费的 SaaS 价格风险敞口
-
Stripe — 通过流程中途切换使用已归档价格(H1 #1328278)
- 子类:购物车状态 TOCTOU/取消后仍交付(结账时的价格版本竞态)
- 攻击载荷:商家将旧价格归档(例如 $5,而新价格为 $50)。买家通过新付款链接开始结账,然后在流程中途将
price_id切回已归档价格。Stripe 收取 $5;订阅则按新档位开通 - 根本原因:付款链接会验证“是否启用”,价格对象会验证“是否存在”——但缺少“price.active AND price ∈ link.allowed_prices”这一联合检查
- 年份:2021 — Stripe 中危(每个订阅都会造成持续损失)
验证
运行此自测以确认业务逻辑测试准备就绪:
-
API 直接调用测试 — 确认 curl 可以绕过前端验证:
curl --max-time 30 --connect-timeout 10 -s -X POST "https://httpbin.org/post" -H "Content-Type: application/json" -d '{"quantity":-1,"price":0}' | python3 -m json.tool 2>/dev/null | grep -q "quantity" && echo "PASS" || echo "(httpbin may be down)" -
并发请求测试 — 验证并行 curl 能力:
curl --help 2>/dev/null | grep -q "parallel" && echo "PASS: curl parallel support" || echo "NOTE: older curl version" -
整数边界情况 — 确认对边界情况的认知:
echo "-1 0 2147483648 999999999" | grep -q "2147483648" && echo "PASS: overflow edge case present" || echo "FAIL"
这 3 项测试均用于验证业务逻辑探测准备情况。
易踩的坑
- 认为业务逻辑漏洞影响较低——价格篡改、优惠券滥用和退款欺诈都是赏金最高的漏洞之一。不要把它们当成“只是逻辑问题”而轻视。
- 只测试正常路径——漏洞往往藏在边缘情况中。测试负数数量、零价格、兑换时的竞争条件、过期优惠券和并发请求。
- 只测试单个步骤——业务逻辑漏洞通常需要多个步骤的组合(添加到购物车 + 应用优惠券 + 更改数量 + 结账)。测试完整流程。
- 忽略错误处理——边缘情况下的 500 错误往往会暴露未处理的状态,进而导致数据不一致(部分订单、重复扣款、免费商品)。
- 不对比前端与 API——前端可能施加了 API 并未施加的限制。通过直接调用 API 测试所有约束。
- 货币与舍入问题——小数货币处理(例如,0.001 USD)可能产生舍入误差,并在批量操作中累积。
相关技能与攻击链
hunt-race-condition——逻辑流程中的每个唯一性/配额检查都可能存在竞争条件。攻击链原语:业务逻辑(优惠券/额度/促销)+ 竞争条件 → 通过 Turbo Intruder 在单个 TCP 数据包中兑换优惠券 N 次。hunt-idor——信任客户端提供的标识符(order_id、tenant_id、beneficiary_id)的逻辑流程与 IDOR 直接重合。攻击链原语:跳过业务逻辑步骤 + beneficiary_id 上的 IDOR → 从受害者账户转出资金。hunt-api-misconfig——跳过步骤和绕过验证通常与批量赋值字段相邻。攻击链原语:跳过业务逻辑中的邮箱验证 + API 批量赋值(verified:true, role:admin)→ 无需控制邮箱即可实现 ATO。hunt-ato——密码重置、邮箱变更和账户恢复流程中的逻辑漏洞是 ATO 的核心攻击路径。攻击链原语:业务逻辑(更改邮箱时无需重新验证)+hunt-ato路径 2 → 悄无声息地替换受害者邮箱 → 将密码重置邮件发送到攻击者邮箱。security-arsenal——加载业务逻辑探测清单(负数量、十进制溢出、货币互换、通过直接 URL 导航跳过步骤、状态机逆向)和始终被拒绝清单,以避免提交自找的问题。triage-validation——应用 7 问门槛(尤其是 Q4“外部攻击者能否在无需不切实际前提的情况下利用此漏洞?”):逻辑漏洞需要明确的金额/PII/状态影响,而不能只是“流程看起来很奇怪”。
价格篡改——客户端信任模式
SaaS 中最常见的业务逻辑模式:服务器信任客户端请求正文中的 price 字段。客户端发送 "price":0,服务器便以 R$0 创建结账会话,而不是从数据库中查询产品价格。
检测
# 1. Create a purchase with normal flow, capture the request
# 2. Replay with modified price
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://api.target.com/checkout" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"items":[{"id":"premium_product","quantity":1,"price":0}]}'
# 3. Test negative prices
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://api.target.com/api/payments/create" \
-H "Authorization: Bearer $TOKEN" \
-d '{"items":[{"id":"plan","quantity":1,"price":-100}]}'
# 4. Test arbitrary quantities
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://api.target.com/api/checkout" \
-d '{"items":[{"id":"key","quantity":999,"price":0}]}'
指标
- 结账/支付端点返回第三方支付 URL(Stripe、Asaas、MercadoPago)
- 支付 URL 带有
cs_test_前缀(Stripe 测试模式——实际上不会处理付款) - 无论价格值是多少,服务器都会响应购买 ID + 结账 URL
- 产品价格可在 JS 包中看到,但服务器端从未进行交叉核对
验证
- 已确认:以 R$0 创建结账 URL,支付页面加载并显示 R$0.00
- 已确认严重:以 R$0 完成购买,并获得许可证/密钥
- 误报:服务器以“price mismatch”拒绝,或使用服务器端价格查询
相关
hunt-write-gap——当服务器 PATCH/POST 端点缺少验证,导致价格篡改成功时hunt-supabase——PostgREST 通过 anon key 接受价格字段的任意值