高版本触发toString的几种方法
字数 3655
更新时间 2026-02-27 03:12:07
高版本Java反序列化中触发toString的Gadgets教学文档
1. 背景与核心挑战
随着Java版本的演进,特别是从JDK9引入模块系统(JPMS)并在JDK17中强化了强封装(Strong Encapsulation)后,传统的反射调用方法受到了严格限制。关键限制如下:
exports声明:只有被exports声明的包中的类才能被外部代码直接访问。opens声明:只有被opens声明的包中的类才能通过反射访问其私有(private)成员。
这种变化导致许多依赖深度反射的旧有反序列化利用链(Gadget)失效。为了在JDK17及更高版本中实现利用,安全研究者发展出了通过修改当前运行类的模块偏移(module offset)等方法来绕过限制。本文档旨在整合并详细说明在高版本Java环境下,几种可用于触发任意对象toString()方法的Gadget,这是构建完整反序列化攻击链的关键步骤。
2. EventListenerList 触发 toString 链
这是在高版本JDK(如JDK17)中触发toString的首选链,其原理与在JDK8中基本一致。
- 核心类:
javax.swing.event.EventListenerList - 链分析:
EventListenerList在反序列化的readObject方法中,会对其内部维护的监听器列表进行遍历和操作。当列表中包含精心构造的对象时,在反序列化过程中会触发该对象的toString方法。 - 利用工具方法:
public static Object get_EventListenerList(Object obj) { EventListenerList listeners = new EventListenerList(); // 通过反射或其他手段,将目标对象(obj)放入listeners的结构中,使其在反序列化时被调用toString // 具体构造方式通常涉及将对象包装进其内部的`listenerList`数组中 return listeners; } - 触发方式:将上述方法返回的
EventListenerList对象进行序列化,再进行反序列化操作,即可触发嵌入对象的toString()。
3. BadAttributeValueExpException 触发 toString 链
此链在CC5、Fastjson原生链、Jackson原生链中均有应用,但存在明确的版本限制。
- 核心类:
javax.management.BadAttributeValueExpException - 链分析:该异常类在
readObject方法中,会直接调用其val字段的toString()方法。 - 利用工具方法:
public static BadAttributeValueExpException get_BadAttrExpEx(Object obj) { BadAttributeValueExpException exception = new BadAttributeValueExpException(null); // 通过反射将字段`val`的值设置为目标对象(obj) Field valField = BadAttributeValueExpException.class.getDeclaredField("val"); valField.setAccessible(true); valField.set(exception, obj); return exception; } - 版本限制与失效原因:
- JDK7及以前:
BadAttributeValueExpException没有实现自己的readObject方法,因此此链无效。 - JDK8 ~ JDK14:
BadAttributeValueExpException实现了readObject,且其val字段为Object类型,可以接受任何对象,链有效。 - JDK15及以后:
val字段的类型被修改为String。在反序列化过程中,如果val不是String类型,会抛出异常,导致此链完全失效。
- JDK7及以前:
4. HashMap + XString 触发 toString 链
此链在Fastjson原生反序列化利用中也经常被提及。
- 核心类:
java.util.HashMap,com.sun.org.apache.xpath.internal.objects.XString - 链分析:
- 反序列化
HashMap时,在readObject->putVal->hash的计算过程中,会调用键(Key)对象的hashCode()方法。 XString类的hashCode()方法内部会调用this.toString()。- 因此,只要将
HashMap的Key设置为一个XString对象,并在构造该XString时使其m_obj成员指向我们最终想要触发toString的目标对象,即可在反序列化HashMap时达成目的。
- 反序列化
- 利用工具方法:
public static HashMap get_HashMap_XString(Object obj) throws Exception { XString xString = new XString("anything"); // 参数无关紧要 // 通过反射将xString的m_obj字段设置为目标对象(obj) Field objField = XString.class.getDeclaredField("m_obj"); objField.setAccessible(true); objField.set(xString, obj); HashMap map = new HashMap(); map.put(xString, "value"); // 关键:将XString对象作为Key放入HashMap return map; }
5. HotSwappableTargetSource + XString 触发 toString 链
这是Spring框架原生的一条链,需要项目引入Spring AOP依赖。
- 核心类:
org.springframework.aop.target.HotSwappableTargetSource,com.sun.org.apache.xpath.internal.objects.XString - 链分析:此链本质上是上一条
HashMap+XString链的变体,中间增加了HotSwappableTargetSource#equals的调用点。- 反序列化过程最终会调用到
HotSwappableTargetSource的equals方法。 - 在该
equals方法中,会调用其target字段的equals方法。 - 通过将
target设置为一个XString对象(其m_obj指向最终目标),并精心构造比较流程,最终会触发XString的toString。
- 反序列化过程最终会调用到
- 利用工具方法:构造相对复杂,通常涉及创建
HotSwappableTargetSource实例和XString实例,并通过反射设置它们的内部字段,最后将它们放入一个HashMap中作为触发入口。序列化/反序列化该HashMap即可。
6. Hashtable + TextAndMnemonicHashMap 触发 toString 链
这是一个相对较新的触发方式。
- 核心类:
java.util.Hashtable,javax.swing.plaf.synth.TextAndMnemonicHashMap - 链分析:
Hashtable在反序列化的readObject()中,会调用reconstitutionPut方法将元素放入哈希表。- 在
reconstitutionPut中,会进行键(key)的比较,最终可能调用到AbstractMap.equals()方法。 - 在
AbstractMap.equals()中,如果传入的参数m是一个TextAndMnemonicHashMap实例,则会调用m.get(key)。 TextAndMnemonicHashMap.get()方法中,会对传入的key调用toString()方法。- 因此,通过构造
Hashtable和TextAndMnemonicHashMap,并控制key为我们最终的目标对象,即可在反序列化Hashtable时触发任意toString。
- 利用工具方法:
public static Hashtable get_Hashtable_TextMap(Object obj) throws Exception { TextAndMnemonicHashMap textMap = new TextAndMnemonicHashMap(); // 构造Hashtable,使其在比较时传入的`m`为textMap,并且比较的key是目标对象(obj) Hashtable table = new Hashtable(); // 具体构造涉及通过反射修改内部状态,将obj设置为比较的key, // 并确保table中的某个entry在reconstitutionPut时与textMap进行比较。 // 构造略复杂,需仔细控制table和textMap的内容。 return table; }
7. 总结与选择建议
| Gadget 组合 | 适用JDK版本 | 依赖 | 特点 |
|---|---|---|---|
| EventListenerList | 全版本(高版本首选) | JDK自带(Swing) | 稳定,与低版本无差异,是JDK17+环境下的可靠选择。 |
| BadAttributeValueExpException | 仅限 JDK8 ~ JDK14 | JDK自带(JMX) | 构造简单直接,但被JDK15+彻底封堵。 |
| HashMap + XString | 全版本(需考虑模块访问) | JDK自带 | 依赖XString的内部访问,在强封装下可能需要模块偏移技巧。 |
| HotSwappableTargetSource + XString | 全版本(需考虑模块访问) | Spring AOP | Spring环境下的利用链,同样依赖XString。 |
| Hashtable + TextAndMnemonicHashMap | 全版本(需考虑模块访问) | JDK自带(Swing) | 较新的利用点,构造略复杂,但提供了另一种触发途径。 |
教学建议:
- 环境适配:首先明确目标Java版本。对于JDK15+,应优先研究
EventListenerList链。 - 理解原理:掌握每条链的触发入口(如
readObject、equals、hashCode)和最终的toString调用点。 - 构造练习:在安全实验环境中,尝试编写和调试上述工具方法,理解每一步反射设置的目的。
- 组合利用:触发
toString通常只是第一步,需要将它与能够执行命令或造成危害的“后半部分链”(如TemplatesImpl)结合,才能形成完整的反序列化漏洞利用。
(注:本文档内容基于所提供链接的技术文章进行整合与阐述。关于具体的反射字段设置、绕过模块强封装的详细代码、以及如何与恶意类链拼接形成完整利用,链接中未提供全部代码细节,需结合Java安全编程知识进行深入研究与实践。)