- 类别:common 别名:— 优先级:—
- 作者:—
- 依赖:
xalan:xalan:2.6.0
构造一个 Xalan 的 org.apache.xpath.objects.XStringForFSB 对象作为「跳板」,利用其继承自 XString 的 equals(Object) 会调用参数对象 toString() 的特性,把上游触发的一次 equals() 转换为对下游任意对象的 toString() 调用。是打通 Equals → ToString 的桥接构件,等价于经典 XString.equals()→toString() 跳板的 XStringForFSB 变体。
- 入口
tags:Equals—— 承接一个「会触发equals()比较」的上一环(如 HashMapEquals、HashTableEquals、ConcurrentHashMapEquals 等 HashMap 键碰撞类 gadget)。 - 衔接
nextTags:ToString—— 之后需接一个「其toString()会触发危险逻辑」的下游 gadget(如FastjsonToString1、JacksonToString、XBeanToString等)。 excludes:无。
本类不含基类,直接实现 Gadget 接口,逻辑集中在 getObject() 与 invoke():
@GadgetTags(tags={"Equals"}, nextTags={"ToString"})
public class XalanXStringToString3 implements Gadget {
public Object getObject() throws Exception {
Object xStringForFSB =
Reflections.createWithoutConstructor("org.apache.xpath.objects.XStringForFSB");
Reflections.setFieldValue(xStringForFSB, "m_obj", null); // 置空 m_obj,规避构造/取值副作用
return xStringForFSB;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object obj2 = chain.doCreate(context); // 内层对象:真正要触发 toString() 的目标
Object obj1 = this.getObject(); // 本层跳板:XStringForFSB
Object[] objects = new Object[]{obj1, obj2}; // 约定:返回 {跳板, 目标} 二元组
return objects;
}
}逐段解释:
getObject()构造跳板:XStringForFSB的正常构造函数需要一个FastStringBuffer及起止位置,不便直接实例化,故用Reflections.createWithoutConstructor(...)绕过构造方法(Unsafe/反射分配)直接得到裸对象;再Reflections.setFieldValue(xStringForFSB, "m_obj", null)把承载底层缓冲区的字段m_obj显式置为null,避免序列化/比较过程中对未初始化的FastStringBuffer触碰而抛异常,使跳板保持「无害且稳定」。invoke()组装二元组:与同族一致——先chain.doCreate(context)取内层目标对象obj2,再造本层跳板obj1,返回Object[]{obj1, obj2}交由上游消费。
触发原理:本 gadget 只产出 {跳板, 目标} 二元组,实际发起调用的是上游 Equals 类 gadget。以 HashMapEquals 为例,其 invoke 中 Object[] objects = (Object[]) chain.doCreate(context) 取回本二元组,PayloadHelper.makeMap(objects[0], objects[1]) 造出键会碰撞的 HashMap;反序列化 HashMap.readObject() 时对碰撞键调用 obj1.equals(obj2)。obj1 为 XStringForFSB,其继承自 XString 的 equals 执行 str().equals(obj2.toString()),从而触发 obj2.toString(),跳入 ToString 环。annotation 的 description 即为该路径:XXX#equals() => AXStringForFSB#equals => YYY#toString()。
本类无 @Param(gadgets.json 中 params 为空);跳板对象与目标对象均由链上下文自动装配,无用户可配字段。
- 依赖
xalan:xalan:2.6.0(org.apache.xpath.objects.XStringForFSB由 Xalan 提供;JDK 内置com.sun.org.apache.xpath.internal下有等价实现,对应 javanative 分类的XString*系列)。 - 与同族 XalanXStringToString1(基类
XString,可直接new XString(""))、XalanXStringToString2(XStringForChars,预置m_strCache)原理一致;本类差异在于所用子类为XStringForFSB,且因其无便捷构造函数而采用createWithoutConstructor+ 置空m_obj的方式生成跳板。 - 关键坑点:
HashMap键碰撞路径在equals之前会先调用键的hashCode()(见 HashMapEquals 注解提示),跳板需能安全计算hashCode;m_obj=null的设置正是为了让XStringForFSB在比较/哈希过程中不因未初始化缓冲区而报错。提供XStringForChars/XStringForFSB两个变体,便于在不同 Xalan 版本或白名单环境下择一绕过。
自由构件,未直接出现在预设链(usedInChains 为空)。可在需要「equals 转 toString」的自定义二次跳板场景中手动组合,例如 Hessian/JSON 反序列化里以 toString 作为最终 sink 触发点的链路。
- 上游(
tags=Equals,即nextTags=Equals的 gadget):HashMapEquals、HashTableEquals、ConcurrentHashMapEquals。 - 下游(
nextTags=ToString):FastjsonToString1、JacksonToString、XBeanToString等以toString()为触发点的 gadget。 - 同族:XalanXStringToString1(
XString基类版)、XalanXStringToString2(XStringForChars版)。