高版本 JDK 对经典 JNDI 注入链做了多轮收紧,但这并不等于 JNDI 完全不可利用。核心变化是“远程类加载”越来越难,而利用思路逐渐转向“本地类利用”“本地工厂利用”和“反序列化链利用”。
历史上,攻击者常通过 RMI / LDAP 返回恶意 Reference,诱导目标从远程加载恶意类。
后来高版本 JDK 开始限制这类行为:
- RMI 从
JDK 6u132、7u122、8u113起收紧 - LDAP 从
JDK 11.0.1、8u191、7u201、6u211起收紧
也就是远程 ObjectFactory 加载不再默认允许。
JEP 290 引入了输入过滤机制,用来限制反序列化类、深度和复杂度。
适用范围:
- JDK 9 正式引入
- JDK 8u121、7u131、6u141 等高版本也补入了类似能力
规范原文:
核心能力:
- 限制允许反序列化的类
- 限制对象深度和复杂度
- 为 RMI 调用提供类过滤机制
- 支持通过配置定义过滤策略
经典“远程类加载”受限后,常见思路转为:
- 利用受害者本地 CLASSPATH 中已有类
- 利用本地工厂类触发方法调用
- 通过 LDAP 返回序列化对象,走反序列化 Gadget 链
思路是:
- 不再依赖远程恶意类
- 改为找目标本地已有的可利用工厂类
- 让 JNDI 返回的
Reference调用这些本地类完成危险行为
公开高频思路是利用 Tomcat 的:
org.apache.naming.factory.BeanFactory
再进一步调用:
javax.el.ELProcessor#evalgroovy.lang.GroovyShell#evaluate
另一条常见思路是:
- LDAP 不返回远程类加载对象
- 而是直接返回恶意序列化数据
- 目标在处理
javaSerializedData时触发本地 Gadget 链
也就是把 JNDI 注入与 Java 反序列化利用结合起来。
高版本场景下,重点不再是“起一个恶意类服务器就能打”,而是:
- 目标本地有哪些类
- 应用是否带 Tomcat、Groovy、EL 等组件
- 是否存在可用 Gadget
- JEP 290 是否放行相关类
这是判断是否还能走经典链的第一步。
重点确认是否存在:
- Tomcat 相关类
- EL 相关类
- Groovy
- 常见反序列化 Gadget 依赖
区分:
- RMI 路径
- LDAP 路径
Reference利用javaSerializedData利用
即使有 Gadget,也可能被过滤器挡掉。
高版本只是缩小经典利用面,不代表所有 JNDI 风险都消失。
不要把用户输入直接交给 lookup()。
明确限制 LDAP、RMI 等外部命名服务的访问。
结合 JEP 290 或应用层白名单进一步减少可利用面。
目标类路径里的 Tomcat、Groovy、EL、Commons 类越少,可利用面越小。
- 先确认 JDK 版本和
trustURLCodebase限制范围 - 再确认目标本地是否存在 BeanFactory、EL、Groovy 等可利用类
- 再判断是
Reference利用还是javaSerializedData反序列化利用 - 检查是否启用了 JEP 290 以及过滤策略
- 不把“高版本 JDK”误判为“天然安全”