作者:Y4er
原文鏈接:https://y4er.com/post/cve-2022-22954-vmware-workspace-one-access-server-side-template-injection-rce/

安裝環境

r師給的鏡像 identity-manager-21.08.0.1-19010796_OVF10.ova,導入ova的時候要設置下fqdn,不然安裝時鏈接數據庫會報錯。

1.png

分析

這個老外的推特中有一點點可以參考的信息

2.png

有兩個報錯信息,我們先找到這個模板所在。

看路由是在catalog-portal app下,cd到/opt/vmware/horizon/workspace/webapps/catalog-portal,然后把jar包拖出來解壓之后,grep -irn "console.log"

發現在lib/endusercatalog-ui-1.0-SNAPSHOT-classes.jar!/templates/customError.ftl:61這個地方存在模板注入

3.png

freemarker官網文檔中給出了安全問題的提示 https://freemarker.apache.org/docs/ref_builtins_expert.html#ref_builtin_eval

4.png

確認了這個地方就是freemarker ssti的地方。

接著看哪個路由可以渲染這個模板,找到了com.vmware.endusercatalog.ui.web.UiErrorController#handleGenericError

5.png

這個函數沒有requestMapping,其中errorObj由參數傳入,查找函數調用,尋找從requestMapping進來的控制器能調用到這個函數的。

endusercatalog-ui-1.0-SNAPSHOT-classes.jar這個jar包是一個spring項目

6.png

有幾個控制器,其中UiErrorController控制器有兩個requestMapping

7.png

這兩個路由均可以走到getErrorPage

8.png

getErrorPage會根據handleUnauthorizedError和handleGenericError兩個函數拿到需要渲染的模板

其中handleUnauthorizedError只有一個分支可以進入handleGenericError

9.png

到這里,想要控制errorObj,則整個數據流向如圖

10.png

我們需要讓其走到handleGenericError才可以rce。

但是此時有一個問題,如果直接訪問這兩個requestMapping,我們無法控制javax.servlet.error.message,也就無法控制errorObj,所以找一找哪個控制器跳轉過來的。

com.vmware.endusercatalog.ui.web.UiApplicationExceptionResolver類中,通過@ExceptionHandler注解標明這是一個異常處理類。

11.png

當程序直接拋出Exception類型的異常時會進入handleAnyGenericException,最終都會返回/ui/view/error,并且設置了errorObj所需要的Attribute

request.setAttribute("javax.servlet.error.status_code", responseCode);
request.setAttribute("javax.servlet.error.message", errorJson);
request.setAttribute("javax.servlet.error.exception_type", ex.getClass());

errorJson來自于LocalizationParamValueException異常的getArgs。

12.png

即自身args屬性,通過構造函數的第二個參數傳入

13.png

如果我們可以控制拋出異常的參數,就可以把freemarker的payload傳入errorObj。

失敗的exception

然后我找到了com.vmware.endusercatalog.ui.web.WorkspaceOauth2CodeVerificationController#authorizeError

14.png

嘗試構造一下

https://id.test.local/catalog-portal/ui/oauth/verify?error=1&error_description=a

15.png

直接302了,調試發現errorMessage確實已經有我們的惡意值1了,但是被sendRedirect,而不是handleGenericError。

16.png

上文講到必須要handleGenericError才能return customError。調試發現

isSpecificUnauthError(excpClass)為false,this.isMdmOnlyUnauthorizedAccessError(request, excpClass)也為false。

    private boolean isSpecificUnauthError(String exceptionClass) {
        return Predicates.or(new Predicate[]{this::isDeviceRecordNotFoundError, this::isUserMismatchError, this::isMdmAuthUnhandledError, this::isDeviceStateInvalidError, this::isExternalUserIdNotFoundError}).apply(exceptionClass);
    }

isSpecificUnauthError過不去,因為com.vmware.endusercatalog.ui.web.WorkspaceOauth2CodeVerificationController#authorizeError拋出的異常是AuthorizationCodeFailedRetrievalException,并非DeviceRecordNotFoundException、UserMismatchException、MdmAuthUnhandledException、DeviceStateInvalidException、ExternalUserIdNotFoundException之一,這個死繞不過去。

isMdmOnlyUnauthorizedAccessError中this.isMdmOnlyMode(request)永為false

17.png

因為((TenantAdapters)adapters).isMdmOnlyMode()一直追溯到com.vmware.endusercatalog.repositories.TenantAdapters#getAdapterAttributesOptional

18.png

當程序配置好之后this.adapters就有了AdapterType.WORKSPACE

    public boolean isWorkspaceConfigured() {
        return this.getAdapterAttributesOptional(AdapterType.WORKSPACE).isPresent();
    }

而取反之后為false。

    public boolean isMdmOnlyMode() {
        return !this.isWorkspaceConfigured();
    }

所以isMdmOnlyUnauthorizedAccessError判斷永為false,所以這條路走不通了。

真正的exception

回頭看com.vmware.endusercatalog.ui.UiApplication,注解聲明自動裝配com.vmware.endusercatalog.auth

19.png

com.vmware.endusercatalog.auth.interceptor.AuthContextPopulationInterceptor

20.png

build函數

        public AuthContext build() {
            return new AuthContext(this);
        }

withDeviceId和withDeviceType分別設置自身的deviceId和deviceType字段。然后build()函數new了一個AuthContext,跟進到com.vmware.endusercatalog.auth.AuthContext#AuthContext構造函數

21.png

這里拋出了一個InvalidAuthContextException異常,參數也可控,if判斷只需要讓this.deviceId、this.deviceType不為空即可。

22.png

payload

23.png

有個坑,host可以為localhost,可以為域名,但是不能為ip,因為ip對不上fqdn。

后利用

寫shell在/opt/vmware/horizon/workspace/webapps/catalog-portal/tomcat目錄下,發現post會校驗csrf,導致哥斯拉連不上,打入一個listener的內存馬就可以了。

文筆垃圾,措辭輕浮,內容淺顯,操作生疏。不足之處歡迎大師傅們指點和糾正,感激不盡。


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