Skip to content

Latest commit

 

History

History
59 lines (46 loc) · 5.43 KB

File metadata and controls

59 lines (46 loc) · 5.43 KB

Xalan XStringForFSB 调用toString(XalanXStringToString3)

  • 类别:common 别名:— 优先级:—
  • 作者:—
  • 依赖xalan:xalan:2.6.0

作用

构造一个 Xalan 的 org.apache.xpath.objects.XStringForFSB 对象作为「跳板」,利用其继承自 XStringequals(Object) 会调用参数对象 toString() 的特性,把上游触发的一次 equals() 转换为对下游任意对象的 toString() 调用。是打通 Equals → ToString 的桥接构件,等价于经典 XString.equals()→toString() 跳板的 XStringForFSB 变体。

链接标签

  • 入口 tagsEquals —— 承接一个「会触发 equals() 比较」的上一环(如 HashMapEqualsHashTableEqualsConcurrentHashMapEquals 等 HashMap 键碰撞类 gadget)。
  • 衔接 nextTagsToString —— 之后需接一个「其 toString() 会触发危险逻辑」的下游 gadget(如 FastjsonToString1JacksonToStringXBeanToString 等)。
  • 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 为例,其 invokeObject[] objects = (Object[]) chain.doCreate(context) 取回本二元组,PayloadHelper.makeMap(objects[0], objects[1]) 造出键会碰撞的 HashMap;反序列化 HashMap.readObject() 时对碰撞键调用 obj1.equals(obj2)obj1XStringForFSB,其继承自 XStringequals 执行 str().equals(obj2.toString()),从而触发 obj2.toString(),跳入 ToString 环。annotation 的 description 即为该路径:XXX#equals() => AXStringForFSB#equals => YYY#toString()

参数(@Param)

本类无 @Paramgadgets.jsonparams 为空);跳板对象与目标对象均由链上下文自动装配,无用户可配字段。

适用版本与原理要点

  • 依赖 xalan:xalan:2.6.0org.apache.xpath.objects.XStringForFSB 由 Xalan 提供;JDK 内置 com.sun.org.apache.xpath.internal 下有等价实现,对应 javanative 分类的 XString* 系列)。
  • 与同族 XalanXStringToString1(基类 XString,可直接 new XString(""))、XalanXStringToString2XStringForChars,预置 m_strCache)原理一致;本类差异在于所用子类为 XStringForFSB,且因其无便捷构造函数而采用 createWithoutConstructor + 置空 m_obj 的方式生成跳板。
  • 关键坑点:HashMap 键碰撞路径在 equals 之前会先调用键的 hashCode()(见 HashMapEquals 注解提示),跳板需能安全计算 hashCodem_obj=null 的设置正是为了让 XStringForFSB 在比较/哈希过程中不因未初始化缓冲区而报错。提供 XStringForChars/XStringForFSB 两个变体,便于在不同 Xalan 版本或白名单环境下择一绕过。

所属预设链

自由构件,未直接出现在预设链(usedInChains 为空)。可在需要「equalstoString」的自定义二次跳板场景中手动组合,例如 Hessian/JSON 反序列化里以 toString 作为最终 sink 触发点的链路。

关联