星期五实验室
阅读须知
星期五实验室的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息造成的直接或间接后果和损失,均由使用者本人负责。
星期五实验室拥有对此文章的修改、删除和解释权限,如转载或传播此文章,需保证文章的完整性,未经授权,不得用于其他。
简介
受影响的版本:
-
VMware WorkSpace ONE Access Appliance:Version 21.08.01、21.08.0.0、21.10.0.1、20.10.0.0
-
VMware Identity Manager Appliance:Version 3.3.6、3.3.5、3.3.4、3.3.3
-
VMware Realize Automation:Version 7.6
环境搭建
http://file.xipudata.com/?dir=/2_software/Vmware/Horizon8
http://www.360doc.com/content/20/1028/12/19798709_942786717.shtml
-
网络设置为nat模式 -
打开ova文件时,设置FQDN -
第一次打开虚拟机需要自行修改密码 -
成功打开虚拟机后,可以设置允许ssh远程登录
-
虚拟机默认开启防火墙,为了方便后面的远程调试,可以把防火墙关闭(systemctl stop iptables.service)
原理分析
https://vmware-gs.my.salesforce.com/sfc/p/#f40000003u6t/a/5G0000002Nla/9COLfZG7uu8iDjLoZTis5Ltzmd1H87iToXs9uLZF8IU
1.打开要调试的源码文件并设置dependencies
2.IDEA添加一个远程调试
3.远程服务器设置启动选项
vim /opt/vmware/horizon/workspace/bin/setenv.sh
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
systemctl restart horizon-workspace.service #重启服务
systemctl stop iptables.service #关闭防火墙
private String handleGenericError(HttpServletRequest request, HttpServletResponse response, Map<String, Object> model, boolean isAWJade, boolean garnetAndAbove, String excpClass, int errorCode, String errorMessage) {
String localizedMessageHeader = this.messages.getLocalizedErrorMessage("errorPage.errorHeading", request.getLocale(), (Object[])null);
String localizedMessage = this.messages.getLocalizedErrorMessage(this.getLocalizedMessageKey(excpClass), request.getLocale(), (Object[])null);
if (errorCode != -1) {
response.setStatus(errorCode);
}
model.put("errorObj", errorMessage);
model.put("messageHeader", localizedMessageHeader);
model.put("genericErrorMsg", localizedMessage);
model.put("contextPath", request.getContextPath());
....
return "customError";
}
com.vmware.endusercatalog.ui.web.UiErrorController#getErrorPage
com.vmware.endusercatalog.ui.web.UiErrorController#handleUnauthorizedError
@RequestMapping({"/ui/view/error"})
public String sendError(HttpServletRequest request, HttpServletResponse response, Map<String, Object> model) {
int errorCode = (Integer)request.getAttribute("javax.servlet.error.status_code");
String errorMessage = (String)request.getAttribute("javax.servlet.error.message");
this.logFor(errorCode, "Error status code: {}, error message: {}", errorCode, errorMessage);
String exClass = request.getAttribute("javax.servlet.error.exception_type") instanceof Class ? ((Class)request.getAttribute("javax.servlet.error.exception_type")).getCanonicalName() : "";
return this.getErrorPage(request, response, model, errorCode, errorMessage, exClass);
}
@RequestMapping({"/error"})
public String sendUnhandledError(HttpServletRequest request, HttpServletResponse response, Map<String, Object> model) {
int errorCode = request.getAttribute("javax.servlet.error.status_code") == null ? -1 : (Integer)request.getAttribute("javax.servlet.error.status_code");
String errorMessage = request.getAttribute("javax.servlet.error.message") == null ? "" : (String)request.getAttribute("javax.servlet.error.message");
String exClass = request.getAttribute("javax.servlet.error.exception_type") instanceof Class ? ((Class)request.getAttribute("javax.servlet.error.exception_type")).getCanonicalName() : "";
String errorObj = "{"code":"" + errorCode + "", "message":"" + errorMessage + ""}";
return this.getErrorPage(request, response, model, errorCode, errorObj, exClass);
}
private String getErrorPage(HttpServletRequest request, HttpServletResponse response, Map<String, Object> model, int errorCode, String errorMessage, String exClass) {
...
String errorPage = (String)Optional.of(errorCode).filter(this::isErrorTypeUnauthorized).map((errCd) -> {
return this.handleUnauthorizedError(request, response, model, isAWJade, garnetAndAbove, exClass, errCd, errorMessage);
}).orElseGet(() -> {
return this.handleGenericError(request, response, model, isAWJade, garnetAndAbove, exClass, errorCode, errorMessage);
});
return StringUtils.hasText(errorPage) ? errorPage : null;
}
private String handleUnauthorizedError(HttpServletRequest request, HttpServletResponse response, Map<String, Object> model, boolean isAWJade, boolean garnetAndAbove, String excpClass, int errorCode, String errorMessage) {
String uiRequestId = Objects.nonNull(request.getAttribute("UI_REQUEST")) ? ((UiRequest)request.getAttribute("UI_REQUEST")).getRequestId() : null;
if (isAWJade) {
...
} else {
return (String)Optional.ofNullable(excpClass).filter(this::isSpecificUnauthError).map((excepClass) -> {
return this.handleGenericError(request, response, model, isAWJade, garnetAndAbove, excpClass, errorCode, errorMessage);
}).orElseGet(() -> {
...
if (this.isMdmOnlyUnauthorizedAccessError(request, excpClass)) {
return this.handleGenericError(request, response, model, isAWJade, garnetAndAbove, excpClass, errorCode, errorMessage);
} else {
...
}
});
}
}
但是直接访问路由,无法控制errorObj(在/ui/view/error中是errorMessage),因此还需要找到其他调用上述两条路由且能控制errorObj的路由。在com.vmware.endusercatalog.ui.web.UiApplicationExceptionResolver#resolveException中会返回/ui/view/error,且该类可以控制errorObj,如下图:
总结
GET /catalog-portal/ui?deviceType=
GET /catalog-portal/hub-ui?deviceType=
GET /catalog-portal/hub-ui/byob?deviceType=
GET /catalog-portal/ui/oauth/verify?deviceType=
GET /catalog-portal/ui/oauth/verify?deviceType=
参考链接:
https://core.vmware.com/vmsa-2022-0011-questions-answers-faq
https://nosec.org/home/detail/4988.html
https://www.carlstalhood.com/vmware-access/
https://kb.vmware.com/s/article/88099
https://freemarker.apache.org/docs/ref_builtins_expert.html#ref_builtin_eval
https://blog.csdn.net/qq_25215821/article/details/102490466
FRIDAY LAB
扫二维码|关注我们
星期五实验室
FRIDAY LAB
原文始发于微信公众号(星期五实验室):CVE-2022-22954 VmwareONEAccess漏洞复现
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论