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. 01API サブドメインの公開操作の確認
  2. 02JavaScript バンドルで見つけたエンドポイントの調査
  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認証なしでデータにアクセスできる可能性があります範囲を限定したサンプルを 1 件検証します
認証なしの 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 の Content-Type を確認してください。
  • ページネーションによって、検証がデータ収集になる可能性があります。 アクセス制御の不備を示すのに必要な最小のページをリクエストしてください。データセットを列挙しないでください。
  • POST、PATCH、PUT、DELETE は状態を変更します。 明示的な許可を得て、テスト用に作成した合成オブジェクトのみを操作してください。
  • 認証テストによってアカウントがロックされたり、アラートが発生したりする可能性があります。 承認済みのテスト用 ID と、合意したリクエスト頻度を使用してください。

検証

  • 同じ操作が認証なしで成功し、想定されるネガティブコントロールでは拒否されることを確認します。
  • 読み取りの場合は、保護対象のデータ種別を示すのに必要な、最小限のサニタイズ済みサンプルのみを保持します。
  • 書き込みの場合は、同じ合成オブジェクトの作成、取得、更新、削除、およびクリーンアップを記録します。
  • URL、メソッド、想定されるポリシー、観測された動作、ID、タイムスタンプ、コントロールの結果、テストの制限を記録します。

コメント