mcpField
A
api-noauth-hunt

api-noauth-hunt

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

关于 api-noauth-hunt

这项安全测试技能用于发现可能缺少必要身份验证或授权的 API 操作。它侧重有限范围的只读探测;任何更改状态的测试都要求明确授权,并使用合成记录。

主要功能

  1. 01常见 API 路径探测
  2. 02OpenAPI 与 Swagger 文档检查
  3. 03有限范围的未认证读取验证
  4. 04受保护的合成记录 CRUD 测试
  5. 05证据记录与清理指引

适用场景

  1. 01检查 API 子域是否暴露操作
  2. 02审查 JavaScript 包中发现的端点
  3. 03在授权评估中验证访问控制缺陷

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/uphiago/recon-skills --skill api-noauth-hunt

安装后在 Claude Code 中输入/api-noauth-hunt确认已加载。

详细介绍

API 无认证验证

识别可能无需其数据和业务功能所要求的身份认证或授权即可访问的 API 操作。默认情况下仅进行只读发现。写入验证使用合成记录,并且必须在执行前立即获得明确授权。

适用场景

  • 端口扫描发现非标准端口(3000、5000、8080-8085、9000)上运行着 HTTP 服务。
  • 目标存在 API 子域名(api.target.com、backend.target.com)。
  • JavaScript 包中引用了内部 API 端点。
  • port-service-discovery 在意外端口发现 HTTP 服务后。
  • firebase-supabase-attack 识别出后端 API 后。

前置条件

  • 已安装 curl、python3、jq。
  • 疑似 API 的目标 URL 或 IP:端口。
  • 用于模糊测试的常见 API 路径列表。

运行方法

# Quick API test — try common paths without auth
TARGET="https://api.target.com"
for path in "/" "/api" "/api/v1" "/api/users" "/api/health" "/docs" "/swagger.json"; do
  code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 5 --connect-timeout 5 "$TARGET$path")
  echo "HTTP $code: $TARGET$path"
done

快速参考

信号含义操作
/api/users 或 /api/clients 返回 HTTP 200可能存在未认证的数据访问验证一个范围受限的样本
未认证的 POST 请求返回 HTTP 2xx可能存在未认证的写入停止操作并获取写入授权
/docs、/swagger.json 提供 OpenAPI/Swagger暴露了完整 API 映射枚举所有端点
出错时返回堆栈跟踪暴露内部路径和框架版本映射基础设施
通过意外的方法改变状态可能存在方法级授权缺口使用合成记录复现
无需验证密码即可登录可能存在身份认证绕过使用获批的测试账号验证

流程

阶段 1 — API 发现
TARGET="$1"      # URL or IP:port
OUTDIR="$OUTDIR/api_recon"
mkdir -p "$OUTDIR"

echo "[*] API discovery on $TARGET"

# Common API paths
API_PATHS=(
  "/" "/api" "/api/v1" "/api/v2" "/v1" "/v2"
  "/api/users" "/api/clients" "/api/admin" "/api/health"
  "/api/auth" "/api/login" "/api/register"
  "/api/products" "/api/orders" "/api/contracts"
  "/docs" "/swagger.json" "/swagger.yaml" "/openapi.json"
  "/api-docs" "/swagger-ui.html" "/graphql"
  "/health" "/status" "/version" "/info" "/ping"
  "/actuator" "/actuator/health" "/actuator/info" "/actuator/env"
)

for path in "${API_PATHS[@]}"; do
  code=$(curl -sk -o /tmp/api_probe_$$.tmp -w "%{http_code}" --max-time 5 --connect-timeout 5 "$TARGET$path" 2>/dev/null)

  if [[ "$code" == "200" ]]; then
    body=$(cat /tmp/api_probe_$$.tmp)
    content_type=$(file -b --mime-type /tmp/api_probe_$$.tmp 2>/dev/null)

    # Check if it's JSON (likely API)
    if echo "$body" | python3 -c "import sys,json; json.load(sys.stdin)" 2>/dev/null; then
      record_count=$(echo "$body" | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d) if isinstance(d,list) else 'object')" 2>/dev/null)
      echo "  [API] $path → HTTP 200 (JSON, ${record_count} records)"
    elif echo "$body" | grep -qi "swagger\|openapi"; then
      echo "  [SWAGGER] $path → HTTP 200 (API documentation)"
    elif echo "$body" | grep -qi "graphql"; then
      echo "  [GRAPHQL] $path → HTTP 200"
    else
      echo "  [HTTP] $path → HTTP 200 (${#body} bytes, $content_type)"
    fi
  elif [[ "$code" == "401" || "$code" == "403" ]]; then
    echo "  [AUTH] $path → HTTP $code (protected)"
  elif [[ "$code" == "500" ]]; then
    echo "  [ERROR] $path → HTTP 500 (potential injection point)"
    cat /tmp/api_probe_$$.tmp | head -5
  elif [[ "$code" != "404" && "$code" != "000" ]]; then
    echo "  [$code] $path"
  fi
done
rm -f /tmp/api_probe_$$.tmp
阶段 2 — OpenAPI/Swagger 利用
TARGET="$1"

echo "[*] Extracting API schema..."

# Try multiple Swagger paths
for sw_path in "/swagger.json" "/swagger.yaml" "/openapi.json" "/api/swagger.json" \
  "/api-docs" "/v2/api-docs" "/v3/api-docs"; do
  schema=$(curl -sk --max-time 10 --connect-timeout 10 "$TARGET$sw_path" 2>/dev/null)

  if echo "$schema" | grep -q '"paths"'; then
    echo "[+] Found OpenAPI spec at $sw_path"

    # Extract all endpoints
    echo "$schema" | python3 -c "
import sys, json
spec = json.load(sys.stdin)
paths = spec.get('paths', {})
for path, methods in paths.items():
    for method in methods.keys():
        if method not in ('parameters',):
            print(f'  {method.upper():7s} {path}')
" 2>/dev/null

    # Save for later use
    echo "$schema" > /tmp/openapi_$$.json
    echo "[+] Schema saved to /tmp/openapi_$$.json"
    break
  fi
done
阶段 3 — 已授权的合成记录 CRUD 验证

此阶段会更改服务器状态。只有在测试范围明确允许写入测试,且端点存储的是可丢弃的合成记录时,才能执行。下面的保护措施是有意设置的:请勿移除,也不要替换为现有对象 ID。

TARGET="$1"
ENDPOINT="$2"  # approved test collection
OUTPUT_DIR="${OUTPUT_DIR:-./output}"
PROBE_ID="noauth-test-$(date +%s)"

if [[ "${I_HAVE_EXPLICIT_WRITE_AUTHORIZATION:-no}" != "yes" ]]; then
  echo "Refusing state-changing validation without explicit authorization." >&2
  exit 1
fi

mkdir -p "$OUTPUT_DIR/api-validation"

create_body=$(curl -sk --max-time 10 --connect-timeout 5 \
  -X POST "$TARGET$ENDPOINT" \
  -H "Content-Type: application/json" \
  -d "{\"name\":\"$PROBE_ID\",\"test_record\":true}")
printf '%s\n' "$create_body" \
  > "$OUTPUT_DIR/api-validation/create-response.json"

created_id=$(printf '%s' "$create_body" | jq -r '.id // .uuid // empty')
if [[ -z "$created_id" ]]; then
  echo "Create response did not expose a disposable object ID; stop here." >&2
  exit 1
fi

curl -sk --max-time 10 --connect-timeout 5 \
  "$TARGET$ENDPOINT/$created_id" \
  -o "$OUTPUT_DIR/api-validation/read-response.json"

curl -sk --max-time 10 --connect-timeout 5 \
  -X PATCH "$TARGET$ENDPOINT/$created_id" \
  -H "Content-Type: application/json" \
  -d '{"validation_state":"updated"}' \
  -o "$OUTPUT_DIR/api-validation/update-response.json"

curl -sk --max-time 10 --connect-timeout 5 \
  -X DELETE "$TARGET$ENDPOINT/$created_id" \
  -o "$OUTPUT_DIR/api-validation/delete-response.txt"
阶段 4 — 范围受限的读取验证
TARGET="$1"
ENDPOINT="$2"  # confirmed no-auth endpoint
OUTPUT_DIR="${OUTPUT_DIR:-./output}"

mkdir -p "$OUTPUT_DIR/api-validation"
curl --max-time 15 --connect-timeout 5 -sk \
  "$TARGET$ENDPOINT?page=1&limit=2" \
  -o "$OUTPUT_DIR/api-validation/bounded-sample.json"

jq 'if type == "array" then .[:2] else . end' \
  "$OUTPUT_DIR/api-validation/bounded-sample.json"

注意事项

  • HTTP 200 ≠ API。 某些服务会在意外路径上返回 HTML。请验证 JSON 内容类型。
  • 分页可能让验证演变为数据收集。 请求能够证明访问控制失效的最小页面。不要枚举整个数据集。
  • POST、PATCH、PUT 和 DELETE 会更改状态。 必须获得明确授权,并且只能操作专为测试创建的合成对象。
  • 身份认证测试可能导致账号锁定或触发警报。 请使用获批的测试身份,并遵守约定的请求速率。

验证

  • 确认同一操作在未认证时能够成功,并且预期的负向对照会拒绝该操作。
  • 对于读取,仅保留证明受保护数据类别所需的最少脱敏样本。
  • 对于写入,记录同一个合成对象的创建、检索、更新、删除和清理过程。
  • 记录 URL、方法、预期策略、观察到的行为、身份、时间戳、对照结果和测试限制。

评论

支持 Markdown