ISCC 决赛 Agent 插件管理系统:Java 反序列化任意文件读取
一、题目背景
题目是一个 Agent 插件管理系统,提供插件上传和日志查看功能。附件为 Spring Boot 应用,解包后可以进行源码和配置分析。
整体利用链:
1 | 解包 jar -> 获取 HMAC 密钥 -> 构造合法插件包 -> metadata.ser 触发反序列化 -> 读取目标文件 -> 从日志接口取回内容 |
二、信息收集
解包 agent-core.jar 后重点关注:
1 | BOOT-INF/classes/application.yml |
配置文件中泄露了上传目录和 HMAC 密钥:
1 | app: |
接口:
1 | POST /api/upload |
上传接口参数:
1 | file |
三、插件校验逻辑
插件包需要是:
1 | zip |
解压后至少包含:
1 | manifest.json |
服务端流程:
- 上传插件压缩包。
- 解压到
/app/uploads/{team_id}/extracted。 - 读取
manifest.json。 - 使用
manifest.json中的hmacSignature校验metadata.ser。 - 校验通过后反序列化
metadata.ser。
由于 HMAC 密钥已经从配置文件泄露,因此可以伪造合法签名,让服务端接受我们构造的 metadata.ser。
四、反序列化调用链
反编译关键类后,可以得到调用链:
1 | ResourceRefresher.readObject() |
关键点:
ResourceRefresher是反序列化入口对象。targetPath控制读取路径。FileExporter内部有teamId字段。- 文件内容会写入对应
teamId的日志。
因此只要构造对象关系:
1 | ResourceRefresher |
上传后访问:
1 | /api/logs?team_id=自己的 team_id |
即可取回文件内容。
五、插件包结构
构造后的插件包结构:
1 | exploit_generated.zip |
manifest.json 中需要包含对 metadata.ser 的合法 HMAC 签名。
伪造签名的思路:
1 | hmacSignature = HMAC_SHA256(hmac-key, metadata.ser bytes) |
由于密钥已知,签名校验无法阻止攻击。
六、利用流程
完整流程:
1 | 1. 编译 ExploitBuilder.java |
自动化脚本需要完成两件事:
- 本地构造合法插件包。
- 上传插件并轮询日志接口。
七、简化脚本逻辑
1 | import hmac |
真实解题脚本还需要调用 Java 构造 metadata.ser,并通过 HTTP 上传插件。
八、漏洞总结
本题是典型的“可信校验被密钥泄露绕过 + Java 反序列化”的组合题。
| 环节 | 问题 |
|---|---|
| 配置文件 | HMAC 密钥泄露 |
| 插件校验 | 签名只保证来源可信,但密钥已暴露 |
| 反序列化 | 对上传包中的 metadata.ser 执行反序列化 |
| 业务逻辑 | 可控路径被用于 Files.readAllBytes() |
| 回显方式 | 文件内容写入日志接口 |
九、防护建议
- 密钥不应硬编码在应用包中。
- 插件校验密钥应使用环境变量或密钥管理系统。
- 不要反序列化用户上传内容。
- 如果必须反序列化,使用白名单类和安全序列化格式。
- 文件读取路径必须做白名单限制。
- 日志中不要写入敏感文件内容。
- 上传插件应在沙箱环境中解析和执行。
十、复盘
这题的关键在于把多个小点串起来:配置泄露本身可能只是信息泄露,但它让插件签名机制失效;反序列化本身也不一定直接命令执行,但结合业务类中的文件读取和日志回显,就形成了完整任意文件读取链。
分析这类 Java 题时,建议先从配置、Controller、Service、反序列化类、日志输出五个方向入手,很容易把攻击路径串出来。