Skip to content

Latest commit

 

History

History
58 lines (45 loc) · 5.38 KB

File metadata and controls

58 lines (45 loc) · 5.38 KB

Xalan XStringForChars 调用toString(XalanXStringToString2)

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

作用

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

链接标签

  • 入口 tagsEquals —— 承接一个「会触发 equals() 比较」的上一环(如 HashMapEqualsHashTableEqualsConcurrentHashMapEquals 等 HashMap 键碰撞类 gadget)。
  • 衔接 nextTagsToString —— 之后需接一个「其 toString() 会触发危险逻辑」的下游 gadget(如 FastjsonToString1JacksonToStringXBeanToString 等)。
  • excludes:无。

源码剖析

本类不含基类,直接实现 Gadget 接口,逻辑集中在 getObject()invoke()

@GadgetTags(tags={"Equals"}, nextTags={"ToString"})
public class XalanXStringToString2 implements Gadget {
    public Object getObject() throws Exception {
        XStringForChars xStringForChars = new XStringForChars(new char[0], 0, 0);
        Reflections.set(xStringForChars, "m_strCache", "");   // 预置字符串缓存,规避真正读取 char[]
        return xStringForChars;
    }

    @Override
    public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
        Object obj2 = chain.doCreate(context);                // 内层对象:真正要触发 toString() 的目标
        Object obj1 = this.getObject();                       // 本层跳板:XStringForChars
        Object[] objects = new Object[]{obj1, obj2};          // 约定:返回 {跳板, 目标} 二元组
        return objects;
    }
}

逐段解释:

  • getObject() 构造跳板new XStringForChars(new char[0], 0, 0) 用空字符数组构造一个 XStringForCharsXString 的子类)。随后 Reflections.set(xStringForChars, "m_strCache", "") 通过反射把字符串缓存字段 m_strCache 直接置为空串。XStringstr() 会优先返回 m_strCache,预置缓存后 equals 内部取本对象字符串值时不会去解析空的 char[] 而抛异常,保证跳板自身「无害且稳定」。
  • invoke() 组装二元组:先 chain.doCreate(context) 取得内层对象 obj2(链中后一个 gadget 的产物,即真正希望触发 toString() 的对象),再生成本层跳板 obj1,最后返回 Object[]{obj1, obj2}

触发原理:本 gadget 不自行发起调用,而是把 {跳板, 目标} 交给上游的 Equals 类 gadget 消费。以 HashMapEquals 为例,其 invokeObject[] objects = (Object[]) chain.doCreate(context) 拿到本二元组,再 PayloadHelper.makeMap(objects[0], objects[1]) 造出一个「键会发生哈希碰撞」的 HashMapHashMap.readObject() 重建时对碰撞的两个键调用 key1.equals(key2),即 obj1.equals(obj2)。此处 obj1XStringForChars,其继承自 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.XStringForChars 由 Xalan 提供;JDK 内也内置了 com.sun.org.apache.xpath.internal.objects.XString 的等价实现,对应 javanative 分类下的 XString* 系列)。
  • 与同族 XalanXStringToString1(用基类 XString)、XalanXStringToString3(用 XStringForFSB)原理一致,差异仅在所构造的 XString 子类与需反射预置的字段:本类用 XStringForChars 并预置 m_strCache,以规避空 char[] 在取字符串时报错。
  • 关键坑点:上游若是 HashMap 键碰撞路径,equals 之前会先调用键的 hashCode()(见 HashMapEquals 注解提示),因此跳板对象必须能安全地计算 hashCodeXStringForChars 预置 m_strCache=""hashCode/equals 均可正常执行。

所属预设链

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

关联