- 类别:javanative 别名:— 优先级:—
- 作者:—
- 依赖:
spring-aop:org.springframework.aop.target.HotSwappableTargetSource、jdk:com.sun.org.apache.xpath.internal.objects.XString
构造一个「两键哈希碰撞」的 HashMap,键为两个 HotSwappableTargetSource,使其在 HashMap.readObject 期间触发 HotSwappableTargetSource.equals → JDK 内置 com.sun.org.apache.xpath.internal.objects.XString.equals → 对内层对象调用任意 toString()。是把「原生/Hessian 反序列化入口」转接到「toString 型 sink」的经典跳板,属 CommonsCollections6/K 系列常用的 HashMap 碰撞变体。
- 入口
tags:JavaNativeDeserialize、HessianDeserializeJavaNativeDeserialize—— 承接 Java 原生反序列化入口(HashMap.readObject天然可被 JDK 反序列化触发)。HessianDeserialize—— 同样适用于 Hessian 反序列化场景(Hessian 会调用HashMap的反序列化并可触发键的hashCode/equals)。
- 衔接
nextTags:ToString—— 之后需接一个「入口为toString()」的 gadget(如 JacksonToString、FastjsonToString1、XBeanToString 等)。 excludes:(无)
public Object getObject(Object object) throws Exception {
XString xString = new XString(""); // 空字符串的 XString
HotSwappableTargetSource h1 = new HotSwappableTargetSource(object); // 包装内层目标对象
HotSwappableTargetSource h2 = new HotSwappableTargetSource((Object)xString); // 包装 XString
HashMap map = PayloadHelper.makeMap(h1, h2); // 构造哈希碰撞 Map
return map;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object object = chain.doCreate(context); // 取内层对象(下游 ToString gadget 的产物)
Object getterObject = context.get(ContextTag.FASTJSON_HANDLE_BYPASS_KEY);
Object resultObject = this.getObject(object);
if (getterObject != null) {
return CommonMethod.listWrap(getterObject, resultObject); // Fastjson handle 绕过场景:套一层 List
}
return resultObject;
}触发原理(逐跳):
PayloadHelper.makeMap(h1, h2)生成一个两键的HashMap,并令h1、h2落入同一个桶(哈希碰撞)。反序列化时HashMap.readObject→putVal在同桶内做键比对,触发h1.equals(h2)(或反向)。HotSwappableTargetSource.equals(other)的实现为「两者都是HotSwappableTargetSource时,比较各自target」,于是转为xString.equals(object)(即h2.target.equals(h1.target))。com.sun.org.apache.xpath.internal.objects.XString.equals(Object obj2)内部会执行this.str().equals(obj2.toString()),即对传入的object调用toString()。- 该
object正是chain.doCreate得到的下游 gadget(nextTags=ToString),其toString()被触发后继续展开利用链。
关键点:new XString("") 用空串占位,保证 equals 走到 obj2.toString() 分支而非提前返回;真正的攻击载体是 object(下游对象)。invoke 中对 FASTJSON_HANDLE_BYPASS_KEY 的判断用于 Fastjson autoType/handle 绕过场景——当上下文注入了 getterObject 时,用 CommonMethod.listWrap 把结果再包一层 List,以适配 Fastjson 的解析路径;常规原生/Hessian 场景该值为空,直接返回 HashMap。
本类无 @Param,无用户可配字段;内层对象与上下文(是否 Fastjson 绕过)均由链自动注入。
- 使用 JDK 内置
com.sun.org.apache.xpath.internal.objects.XString(rt.jar自带),因此无需第三方 XML 依赖,仅需目标存在spring-aop的HotSwappableTargetSource。 - JDK 高版本(模块化后)若移除/封装了
com.sun.org.apache.xpath.internal.*,则本变体不可用,需改用 XalanXString1(依赖 xalan:2.6.0 的独立包)。 HotSwappableTargetSource来自 spring-aop,属极常见依赖,落地面广。- 依赖
HashMap碰撞技巧,属纯逻辑跳板,不触及字节码,适配 Java 原生与 Hessian 两类反序列化入口。
自由构件,未直接出现在 51 条预设链中(usedInChains 为空)。是「反序列化入口 → toString sink」的可插拔中间件。
- 下游(
nextTags=ToString):JacksonToString、FastjsonToString1、FastjsonToString2、XBeanToString、RomeToStringBean1/2、SpringAopAspectjweaver。 - 同族变体:XString2(
XStringForChars)、XString3(XStringForFSB)、XalanXString1(xalan 独立包)——用于绕过不同 JDK 版本/黑名单。 - 上游:可由任何
nextTags指向JavaNativeDeserialize/HessianDeserialize的二次反序列化跳板承载。