mcpField
J
js-secrets-extraction

js-secrets-extraction

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

关于 js-secrets-extraction

js-secrets-extraction 是用于 Web 安全测试的技能,可检查 JavaScript 包和源映射中的暴露凭据、端点、路由及源代码。它提供下载、搜索、重建和验证发现结果的步骤,面向授权评估。

主要功能

  1. 01收集并扫描 JavaScript 包
  2. 02发现并重建源映射
  3. 03搜索凭据和密钥模式
  4. 04提取 API、后端 URL 和路由
  5. 05跨端口与应用分块分析
  6. 06提供发现结果验证指导

适用场景

  1. 01在 Web 枚举期间检查 SPA 包
  2. 02通过源映射查找原始代码和凭据
  3. 03从管理应用中发现后端 URL 和 API 路径
  4. 04报告前验证疑似密钥

安装

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

$npx skills add https://github.com/uphiago/recon-skills --skill js-secrets-extraction

安装后在 Claude Code 中输入/js-secrets-extraction确认已加载。

附带文件scripts/scan_js.py

详细介绍

JS Bundle 与 Source Map 分析——机密信息提取

适用场景

  • 完成初步 Web 枚举后,始终执行
  • 发现现代 SPA(React、Angular、Vue)时
  • 目标使用 Firebase、Supabase、Auth0 时
  • 对许多目标而言,收益高于目录扫描

为什么要分析 JS Bundle

现代 JavaScript Bundle(Webpack、Vite、esbuild)通常包含:

  • 硬编码的 API 密钥和令牌
  • 内部 API URL
  • Firebase、Auth0、Supabase 配置
  • 环境变量(VITE_、REACT_APP_、NEXT_PUBLIC_)
  • 内部路由

Bundle 下载与分析

curl --max-time 30 --connect-timeout 10 -s "https://target.com" > index.html
grep -Eo 'src="[^"]*\.js"' index.html | cut -d'"' -f2 | while read js; do
  curl --max-time 30 --connect-timeout 10 -s "https://target.com$js" > "$(basename $js)"
done

# Search for secrets in bundles
grep -rEn "(apiKey|api_key|API_KEY|token|secret|password|clientId|client_id|auth0|firebase|supabase)[\"'\"]?[[:space:]]*[:=][[:space:]]*[\"'\'][^\"'\']{8,}" *.js

Source Map 重建

curl --max-time 30 --connect-timeout 10 -sI "https://target.com/assets/index-abc123.js.map"
curl --max-time 30 --connect-timeout 10 -sI "https://target.com/static/js/main.12345.js.map"

# If HTTP 200, use for reconstruction:
# https://unminify.com
# https://source-map-visualization.netlify.app

真实案例:企业级 Angular SPA 管理后台暴露了 2 个 JS Bundle(各 250KB):

  • 内部 API URL(apiv3.empresa.com.br)
  • Firebase API 密钥(AIzaSy...2GXA)
  • 加密密钥(AD5oDjsJaTJOzLe1Llj9mz)
  • Cloudinary 上传端点

特定端口的 URL 分析

现代部署通常在 443 端口提供主 SPA,在其他端口(8080、8081、8084)提供管理后台/API。务必检查所有已发现端口上的 JS Bundle:

# Check source maps on every open port
for port in 443 8080 8081 8084; do
  curl --max-time 30 --connect-timeout 10 -sI "https://target.com:$port/static/js/main.*.js.map" 2>/dev/null
  curl --max-time 30 --connect-timeout 10 -sI "https://target.com:$port/assets/index-*.js.map" 2>/dev/null
done

管理应用或备用端口应用上的 Source Map,可能暴露与公共 SPA 不同的路由和配置。请分别分析每个获准访问的应用。

管理门户 JS 分析模式

当你在单独的端口上发现管理门户时,其 JS Bundle 通常包含与主站不同的机密信息:

base = "https://target.com:8080"  # Admin portal
js = requests.get(f"{base}/static/js/main.*.js").text

# 1. Extract ALL API URLs
api_urls = re.findall(r'https?://[^\"\'[[:space:]]\\n,)>\\]]+', js)
# 2. Find base API URL (the backend this admin talks to)
# 3. Look for hardcoded credentials, API keys, auth patterns
# 4. Extract route paths for the admin app
routes = re.findall(r'[\"\'](/[a-zA-Z0-9_/.-]*(?:admin|chat|bot|message|user|auth|login|token|config|setting|dashboard|hospital|pharmacy|drug|payment)[a-zA-Z0-9_/.-]*)[\"\']', js, re.IGNORECASE)

Source Map 内容分析(1,200+ 个文件)

当 Source Map 可用时,分析 sourcesContent 数组中的硬编码机密信息:

import json, re
data = json.loads(open("bundle.js.map").read())
all_source = " ".join(data.get("sourcesContent", []))

# Search for credentials in the original source
patterns = {
    "password": r'[\"\']([^\"\']*(?:password|passwd|pwd)[^\"\']*)[\"\']\s*[:=]\s*[\"\']([^\"\']+)[\"\']',
    "token": r'[\"\']([^\"\']*(?:token|jwt|api_key|apikey|secret)[^\"\']*)[\"\']\s*[:=]\s*[\"\']([^\"\']+)[\"\']',
}
for name, pat in patterns.items():
    matches = re.findall(pat, all_source, re.IGNORECASE)
    if matches:
        print(f"[{name}] {matches[:5]}")
  • Cloudinary 上传端点

机密信息正则表达式模式目录

import re

patterns = {
    "Firebase API Key": r'apiKey:\s*[\"\']([^\"\']{30,})',
    "AWS Key": r'(?:AKIA|ASIA)[A-Z0-9]{16}',
    "Google API Key": r'AIza[0-9A-Za-z\\-_]{35}',
    "JWT": r'eyJ[A-Za-z0-9_\\-]{20,}\.[A-Za-z0-9_\\-]{20,}\.[A-Za-z0-9_\\-]{10,}',
    "Mercado Pago": r'APP_USR-[a-f0-9]{8,}',
    "Stripe": r'(?:sk_live|pk_live)_[A-Za-z0-9]{24,}',
    "Auth0 Domain": r'(?:domain|auth0_domain):\s*[\"\']([^\"\']+\.auth0\.com)',
    "Auth0 Client ID": r'(?:client_id|clientId|AUTH0_CLIENT_ID):\s*[\"\']([^\"\']{20,})',
    "Supabase URL": r'(?:supabaseUrl|SUPABASE_URL):\s*[\"\'](https://[^\"\']+\.supabase\.co)',
    "Supabase Key": r'(?:supabaseKey|anonKey|SUPABASE_ANON_KEY):\s*[\"\'](eyJ[A-Za-z0-9_\\-]+\.[A-Za-z0-9_\\-]+\.[A-Za-z0-9_\\-]+)',
    "Heroku": r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}',
    "Generic Secret": r'(?:secret|password|token|key):\s*[\"\']([^\"\']{8,})',
}

批量下载 Bundle 并使用 Grep 搜索

import requests, re, json

base = "https://target.com"
html = requests.get(base).text

# Extract all JS URLs
js_urls = re.findall(r'src="([^"]*\.js)"', html)
for js_url in js_urls:
    if js_url.startswith("/"):
        js_url = base + js_url
    content = requests.get(js_url).text
    for name, pattern in patterns.items():
        matches = re.findall(pattern, content)
        for m in matches:
            if isinstance(m, tuple):
                m = m[0]
            if len(m) > 6:
                print(f"[{name}] {m[:80]}")

注意事项

问题解决方案
Bundle 过大使用 grep -Eo 并指定具体模式
代码经过压缩(名称仅 1 个字符)使用 Source Map 重建代码
匹配结果为误报通过测试 API 端点验证密钥
速率限制在下载 Bundle 之间添加延迟

后端 URL 发现

JS Bundle 经常泄露生产环境的后端 URL,可绕过 CDN/WAF 直接攻击 API:

# Platform-specific backend URL patterns
grep -Eo 'https?://[a-zA-Z0-9.\-]+\.(fly\.dev|azurewebsites\.net|onrender\.com|vercel\.app|netlify\.app)[^"'\'' ]{0,40}' /tmp/*.js
grep -Eo 'https?://[a-zA-Z0-9.\-]+\.(supabase\.co|r2\.dev|blob\.vercel-storage\.com)[^"'\'' ]{0,40}' /tmp/*.js

# Edge function URLs
grep -Eo 'functions/v1/[a-zA-Z0-9_\-]+' /tmp/*.js

# Internal API paths
grep -Eo '["\x60]/api/v1/[a-zA-Z0-9_\-/]+["\x60]' /tmp/*.js
真实案例中的模式
模式平台示例是否为机密信息?
*.fly.devFly.ioht-prod-backend.fly.dev✅ 后端 URL
*.azurewebsites.netAzureconsigpro-api-prod-...✅ 后端 URL
*.onrender.comRenderclickcity-api.onrender.com✅ 后端 URL
*.supabase.coSupabasejxhvjufqtabpeieyhkgk.supabase.co✅ Anon 密钥是公开的;后端 URL 是情报
*.r2.devCloudflare R2pub-xxx.r2.dev✅ 存储 URL
functions/v1/*Supabase Edgeprovision-openrouter-key✅ 端点名称
dpl_*Vercel DPLdpl_BCoyPsxxYLZ...❌ 不是机密信息——公开的部署 ID

验证

# Test Firebase API key
curl --max-time 30 --connect-timeout 10 -s "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=AIza..."
# Test Supabase anon key
curl --max-time 30 --connect-timeout 10 -s "https://PROJECT.supabase.co/rest/v1/users?limit=1" -H "apikey: ANON_KEY" -H "Authorization: Bearer ANON_KEY"
阶段 5——利用 Source Map

如果 .js.map 文件遗留在生产环境中,可还原完整的预编译源代码:

# Find .map files via Wayback Machine
curl --max-time 30 --connect-timeout 10 -s "https://web.archive.org/cdx/search/cdx?url=*.target.com/*&collapse=urlkey&output=text&fl=original&filter=original:.*\.js\.map$" \
  | sort -u > map_urls.txt

# Download and extract source
wget https://target.com/static/app.js.map
node -e "
const map = require('./app.js.map');
map.sources.forEach((src, i) => {
  const fs = require('fs');
  fs.writeFileSync(src.split('/').pop(), map.sourcesContent[i]);
});
print('Extracted ' + map.sources.length + ' source files');
"

# Quick check: does a JS file have an available map?
curl --max-time 30 --connect-timeout 10 -skI "https://target.com/static/app.js.map" | grep "200\|Content-Type"
阶段 6——深度 JS 爬取

递归爬取 JS 文件,查找嵌入其中的 URL、API 和 IP:

# lazyegg — crawls JS files for links, APIs, IPs
python3 lazyegg.py https://target.com
python3 lazyegg.py https://target.com/js/auth.js

# Combine with waybackurls for deep coverage
waybackurls target.com \
  | grep '\.js$' \
  | awk -F '?' '{print $1}' \
  | sort -u \
  | xargs -I{} bash -c 'python3 lazyegg.py "{}" --js_urls --domains --ips' \
  > lazyegg_output.txt

# subjs — extract JS URLs from any URL list
cat all_urls.txt | subjs | tee js_files_full.txt
阶段 7——逐文件 AI 辅助代码审查

JS Bundle 就是源代码,即使经过压缩也一样。严格逐文件(逐代码块)审查,能发现自主 Agent 遗漏的问题:

# 1. Download all JS chunks
curl --max-time 30 --connect-timeout 10 -sk "https://target.com" | grep -Eo 'src="[^"]+\.js[^"]*"' | \
  cut -d'"' -f2 | while read js; do
    curl --max-time 30 --connect-timeout 10 -sk "$js" -o "chunks/$(basename $js)"
  done

# 2. Per-chunk pattern review for dangerous sinks
for chunk in chunks/*.js; do
  echo "=== $chunk ==="
  # eval / new Function (arbitrary code execution)
  grep -Eon 'eval\s*\(|new\s+Function\s*\(' "$chunk"
  # Hardcoded API keys/secrets
  grep -Eon '(?:api[_-]?key|secret|token|password|bearer)\s*[:=]\s*["\x27][^"\x27]{8,}' "$chunk"
  # postMessage without origin check
  grep -Eon 'postMessage\s*\(' "$chunk"
  # Prototype pollution patterns
  grep -Eon '__proto__|constructor\.prototype' "$chunk"
  # Debug/test code in production
  grep -Eoin 'debug|test|staging|localhost' "$chunk"
  # Client-trusted flags
  grep -Eon '(?:isAdmin|isVip|isPremium|isModerator|role)\s*[=:]\s*true' "$chunk"
done > ai_review_findings.txt

# 3. Review findings — each is a CANDIDATE, not confirmed
grep -c "===" ai_review_findings.txt  # files reviewed
grep -c ":" ai_review_findings.txt     # candidate findings

关键要点:让自主 Agent 在整个代码库中“查找漏洞”,会耗费预算且容易遗漏问题。采用固定输出结构逐文件检查,可稳定地发现问题。仍需手动验证每个发现并制作 PoC。

评论

支持 Markdown