CVE-2022-22954 VMware Workspace ONE Access SSTI RCE
2022-4-11 16:0:16 Author: xz.aliyun.com(查看原文) 阅读量:8 收藏

r师给的镜像 identity-manager-21.08.0.1-19010796_OVF10.ova,导入ova的时候要设置下fqdn,不然安装时链接数据库会报错。

这个老外的推特中有一点点可以参考的信息

有两个报错信息,我们先找到这个模板所在。

看路由是在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这个地方存在模板注入

freemarker官网文档中给出了安全问题的提示

https://freemarker.apache.org/docs/ref_builtins_expert.html#ref_builtin_eval

确认了这个地方就是freemarker ssti的地方。

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

这个函数没有requestMapping,其中errorObj由参数传入,查找函数调用,寻找从requestMapping进来的控制器能调用到这个函数的。

endusercatalog-ui-1.0-SNAPSHOT-classes.jar这个jar包是一个spring项目

有几个控制器,其中UiErrorController控制器有两个requestMapping

这两个路由均可以走到getErrorPage

getErrorPage会根据handleUnauthorizedError和handleGenericError两个函数拿到需要渲染的模板

其中handleUnauthorizedError只有一个分支可以进入handleGenericError

到这里,想要控制errorObj,则整个数据流向如图

我们需要让其走到handleGenericError才可以rce。

但是此时有一个问题,如果直接访问这两个requestMapping,我们无法控制javax.servlet.error.message,也就无法控制errorObj,所以找一找哪个控制器跳转过来的。

com.vmware.endusercatalog.ui.web.UiApplicationExceptionResolver类中,通过@ExceptionHandler注解标明这是一个异常处理类。

当程序直接抛出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。

即自身args属性,通过构造函数的第二个参数传入

如果我们可以控制抛出异常的参数,就可以把freemarker的payload传入errorObj。

失败的exception

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

尝试构造一下

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

直接302了,调试发现errorMessage确实已经有我们的恶意值1了,但是被sendRedirect,而不是handleGenericError。

上文讲到必须要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

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

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

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

而取反之后为false。

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

所以isMdmOnlyUnauthorizedAccessError判断永为false,所以这条路走不通了。

真正的exception

经过chybeta、su18、iiusky师傅的指点,回头看com.vmware.endusercatalog.ui.UiApplication,发现注解声明自动装配com.vmware.endusercatalog.auth

com.vmware.endusercatalog.auth.interceptor.AuthContextPopulationInterceptor中是个拦截器,会被自动装配到spring容器中。

build函数

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

withDeviceId和withDeviceType分别设置自身的deviceId和deviceType字段。然后build()函数new了一个AuthContext,跟进到com.vmware.endusercatalog.auth.AuthContext#AuthContext构造函数

这里抛出了一个InvalidAuthContextException异常,参数也可控,if判断只需要让this.deviceId、this.deviceType不为空即可。

payload自己构造吧,有个坑,host可以为localhost,可以为域名,但是不能为ip,因为ip对不上fqdn。

写shell在/opt/vmware/horizon/workspace/webapps/catalog-portal/tomcat目录下,发现post会校验csrf,导致哥斯拉连不上,打入一个listener的内存马就可以了。


文章来源: https://xz.aliyun.com/t/11196
如有侵权请联系:admin#unsafe.sh