- 类别:common 别名:— 优先级:—
- 作者:—
- 依赖:
jdk:javax.sound.sampled.AudioFileFormat$Type(纯 JDK 内置类,无第三方依赖)
利用 JDK 内置类 javax.sound.sampled.AudioFileFormat$Type 的 equals() 会调用参数对象 toString() 这一特性,把「一次 equals 调用」转换成「一次任意对象的 toString 调用」。是 equals → toString 的桥接构件(trampoline),用于把上游的哈希碰撞/equals 触发点接到下游的 toString 型 sink。
- 入口
tags:Equals、NotForJavaSerializableEquals—— 表示本 gadget 需要一个「会触发equals()比较」的上游环(如HashMapEquals/HashTableEquals/ConcurrentHashMapEquals),由它对本 gadget 产出的两个元素调用a.equals(b)。NotForJavaSerializable—— 标记本产物(Object[]数组 +AudioFileFormat$Type未初始化实例)不能走 Java 原生序列化通道(该 Type 实例经createWithoutConstructor生成、字段不完整,原生writeObject会出错),仅适用于 Hessian/JSON 等按字段序列化的入口。
- 衔接
nextTags:ToString—— 本 gadget 之后必须接一个「暴露危险toString()」的 gadget(如 JacksonToString、XBeanToString、FastjsonToString1/2)。 excludes:无。
@GadgetTags(tags={"Equals", "NotForJavaSerializable"}, nextTags={"ToString"})
public class AudioFileFormat$TypeToString implements Gadget {
public Object getObject() throws Exception {
Object type = Reflections.createWithoutConstructor("javax.sound.sampled.AudioFileFormat$Type");
return type;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object obj2 = chain.doCreate(context); // 内层对象:一个 toString 型 gadget 的产物
Object obj1 = this.getObject(); // AudioFileFormat$Type 未初始化实例
Object[] objects = new Object[]{obj1, obj2}; // 成对返回,供上游 equals 消费
return objects;
}
}getObject()用Reflections.createWithoutConstructor(...)通过 Unsafe/反射跳过构造器实例化AudioFileFormat$Type。关键在于:不走构造器就不会给内部的name(类型字符串)字段赋值,使其保持为null。AudioFileFormat$Type的equals()是 JDK 内置逻辑,等价于toString().equals(that.toString());当自身toString()(即name)为null时,会走到「比较对方toString()是否为null」的分支,从而对参数对象obj2调用obj2.toString()。这一步正是触发下游 toString sink 的引信。invoke先chain.doCreate(context)取得内层 toString gadget 的产物obj2,再把obj1(Type 实例)与obj2打包成Object[]{obj1, obj2}返回。上游的Equals型 gadget(如HashMapEquals)会把数组两元素放进哈希容器制造碰撞,反序列化时触发obj1.equals(obj2)→obj2.toString()。
关键点:本 gadget 自身不发起任何比较,只负责「构造一个 equals 会回调 toString 的载体」并与目标对象配对;真正的 equals 触发由上游容器 gadget 完成,真正的 RCE 由下游 toString gadget 完成。
本类无 @Param 可配参数;目标 toString 载体由 chain.doCreate 注入的内层对象决定。
- 依赖仅为 JDK 内置
javax.sound.sampled.AudioFileFormat$Type,无第三方库要求。 - 依赖
equals()→toString()的 JDK 语义,该行为在各主流 JDK 版本稳定存在。 - 因产物含未初始化实例且以
Object[]承载,NotForJavaSerializable标签限定其只能用于非 Java 原生、按字段重建对象的序列化协议(Hessian、Fastjson、Jackson 等)。 - 与
AudioFormat(Encoding 版)原理完全一致,属同一族的可替换构件,用于绕过针对某一具体类的黑名单。
自由构件,未直接出现在 51 条预设链中(usedInChains 为空)。可在 Hessian/JSON 二次反序列化场景中手动组合:HashMapEquals → AudioFileFormat → JacksonToString → …。
- 上游(消费
tags=Equals,即nextTags=Equals):HashMapEquals、HashTableEquals、ConcurrentHashMapEquals、HotSTSourceEquals、Rdn - 下游(提供
tags=ToString):JacksonToString、XBeanToString、FastjsonToString1/FastjsonToString2、RomeToStringBean1/2、SpringAopAspectjweaver - 同族:AudioFormat(
AudioFormat$Encoding版本,等价替换)