SECURENVOY MFA 9.4.513
CVE-2024-37393

VULNERABILITY RESPONSIBLE DISCLOSURE
SECURENVOY ZERO TRUST SOLUTION

TL; DR

  • Optistream conducted a red team security assessment for a client exposing a SecurEnvoy MFA 9.4.513 instance on the Internet
  • A detailed analysis revealed several critical vulnerabilities (CVE-2024-37393[1])
  • Exploiting these vulnerabilities, auditors managed to exfiltrate Active Directory data from the Internet
  • Optistream collaborated with the vendor to fix these issues before disclosure
  • If you use SecurEnvoy MFA, update to version >= 9.4.514 immediately (release notes[2])

TL; DR

  • Optistream conducted a red team security assessment for a client exposing a SecurEnvoy MFA 9.4.513 instance on the Internet
  • A detailed analysis revealed several critical vulnerabilities (CVE-2024-37393[1])
  • Exploiting these vulnerabilities, auditors managed to exfiltrate Active Directory data from the Internet
  • Optistream collaborated with the vendor to fix these issues before disclosure
  • If you use SecurEnvoy MFA, update to version >= 9.4.514 immediately (release notes[2])

Summary

Our cybersecurity experts encountered SecurEnvoy MFA 9.4.513 during a client engagement and conducted an in-depth analysis of this solution.

Several vulnerabilities and lack of security checks were identified. Optistream promptly informed the vendor of these issues and collaborated closely to address and resolve them(see timeline).

The first vulnerability, discovered during the initial assessment, involved user enumeration. A subsequent, more critical vulnerability was discovered after a deeper analysis of the product. This vulnerability allows unauthenticated users to exfiltrate service directory data by exploiting LDAP injection vulnerabilities in IPC mechanism ("DESKTOP" protocol). This critical flaw makes it possible for outsiders to retrieve SecurEnvoy secret attributes (encrypted 2FA factors) from the directory.

Product description

SecurEnvoy MFA is a widely used software solution providing two-factor authentication (2FA) support for third-party services or appliances (e.g. Citrix, FortiGate...).

SecurEnvoy acts as a RADIUS server and relies on a LDAP service (e.g. Microsoft Active Directory, OpenLDAP) to authenticate its users. It uses in-house password handling of the directory to check 1st factor (relying on LDAP bind method) and extends directory usage to allow checking of a second factor ("PIN code") before granting access to a user. This last factor can be of several types depending on each user account configuration:

Second factors (static or dynamically generated) are stored within specific attributes. During our analysis, we found out that these were stored in two different Active Directory attributes: telexNumber and primaryTelexNumber. These are legacy Active Directory attributes that are repurposed by SecurEnvoy for its own usage.

SecurEnvoy MFA exchanges
SecurEnvoy MFA - 2FA exchanges

DESKTOP protocol

SecurEnvoy MFA service is made of several components and relies on CGI architecture based on Microsoft IIS server. Service is splitted into several .NET binaries that are triggered upon HTTPS user or internal requests (IPC).

We delved into the securectrl.exe binary notably dedicated to user authentication through interactions with the directory service using LDAP queries.

Our investigation revealed the existence of a homemade internal scheme of communication used between the different components (IPC mechanism) that is carried over HTTPS. One part of this mechanism implemented in this binary -we dubbed it "DESKTOP" protocol- is exposed and accessible without authentication through the default endpoint /secserver.

This so made accessible protocol has been investigated by the auditors and several vulnerabilities and weaknesses have been spotted in it. All have been reported and patched by the vendor, we choose to only highlight the most critical vulnerabilities in this blog entry.

VULN 1 - User enumeration

SEVERITY

MEDIUM

ENDPOINT

BINARY

securectrl.exe

/secserver

TESTED VERSIONS

9.4.505 / 9.4.513

When sending POST data with the first line being FLAG=DESKTOP to the /secserver HTTP endpoint, particular piece of code implementing "DESKTOP" protocol is triggered.

Analysis of binary decompiled code helped us at getting a better understanding of the protocol and how different user-controlled parameters were transmitted and processed. The protocol doesn't adhere to the standard format of HTTP POST data as each parameter stands in a separate line. Code analysis allowed us to obtain a list of all the existing parameters handled by the "DESKTOP" protocol and we looked at those used to perform sensitive operations.

Among these parameters, USERID serves at performing user authentication when a special STATUS variable is sent. We were able to get a way to enumerate existing users in the directory bound to SecurEnvoy (e.g. Active Directory) using hereafter protocol message:

Crafted DESKTOP protocol message

This example of request allows an unauthenticated user to check if SomeUser exists within SecurEnvoy directory.

This is made possible because server responses differ depending on whether the user exists or not:

User exists

User doesn't exist

Moreover, debug logs available in our LAB environment show that a specific LDAP query is executed by SecurEnvoy upon receiving this protocol message:

Debug logs extract

SomeUser input is directly reflected into an LDAP query. After some testing, it was determined that we could use the wildcard operator to enumerate usernames from Active Directory. This was achieved by employing a brute-force approach, whereby each character could be individually tested (e.g. j*, jo*, joh*, john).

In the next part of our analysis, we’ll take a closer look at how this query is built.

VULN 2 - LDAP injection (USERID)

SEVERITY

CRITICAL

ENDPOINT

BINARY

securectrl.exe

/secserver

TESTED VERSIONS

9.4.505 / 9.4.513

This one is the most critical vulnerability we found and it allowed us to retrieve sensitive data from our client.

In-depth analysis of securecrtl.exe code revealed us how LDAP queries are built based on inputs provided through this protocol message. For that, we identified securectrl_flagdesktop class allegedly responsible for "DESKTOP" protocol handling, we then took a look at its main method:

→ securecrtl.securecrtl_flagdesktop::flagdesktop
   …
   if (Operators.CompareString(text18, "USERID", false) == 0)
   {
       IL_41D:
       num2 = 39;
       sUserID = TokenServices.SoftTokenUrlDecode(text19);   // (1)
       IL_429:;
   }
   …
   seldap.sUserID = sUserID;
   IL_1F4E:
   num2 = 408;
   string text22 = seldap.getldapuser();

     → SecurEnvoy.Common.seldap::getldapuser
        …
        this.server_loop(new ThreadStart(this.getldapuserthread));

        → SecurEnvoy.Common.seldap::getldapuserthread
           …
           string text3 = this.getuserquery();   // (2)
           …
           directorySearcher.Filter = text3;
flagdesktop control flow

User controls seldap.sUserID (1) (e.g. SomeUser) and getuserquery (whose name was previously observed in debug logs) get called (2). This last function is responsible for constructing an LDAP query based on USERID input variable from the "DESKTOP" message:

→ SecurEnvoy.Common.seldap::getuserquery
   …
   string text2 = this.sUserID;
   …
   string text3 = string.Concat(new string[]
   {
       "(",
       text,
       "=",
       text2,   // (3)
       ")"
   });
   this.mydebug.message("a", "seldap.getuserquery:adding element " + text3, "");
   list.Add(text3);
   …
   string text4 = "(&(" + this.sLdapFilter + ")";   // (4)
   if (list.Count == 1)
   {
       text4 += list[0];
   }
   …
   text4 += ")";
   this.mydebug.message("a", "seldap.getuserquery:Returning:" + text4, "");
   return text4;
getuserquery

The vulnerability resides in this piece of code.

Indeed, text2 variable is user-controlled and processed (3) without any characters filtering during LDAP query construction while this.sLdapFilter used at line (4) contains the following subquery by default (configured in server.ini file):

LdapFilter=(!(objectClass=computer))(&(objectClass=user))
server.ini extract

Finally, the crafted query by getuserquery looks like this after substitutions:

(&(this.sLdapFilter)(text=text2)
(&((!(objectClass=computer))(&(objectClass=user))(samaccountname=<USERID>)

Original goal of this request is retrieving directory information for a specified user based on its account name (sAMAccountName for Active Directory). However, by controlling USERID, an attacker could inject special characters to hijack LDAP queries behavior:

(&((!(objectClass=computer))(&(objectClass=user))(samaccountname=*)(telexNumber=X)

We are able to test a chosen attribute (e.g. telexNumber used for storage of sensitive SecurEnvoy data) against a specific value or pattern.

As with VULN 1, attacker can leverage server responses to conduct a "blind" LDAP injection attack to incrementally guess the content of users' attributes the attacker have access to.

It is thus possible to exfiltrate sensitive SecurEnvoy data (encrypted user data) or any Active Directory attribute. The sensitive point is that these LDAP queries are executed as a privileged user in domain (usually a Domain Administrator), giving so extended rights to the attacker to read dangerous attributes (e.g. ms-MCS-AdmPwd for LAPS passwords in AD environments).

VULN 3 - LDAP injection (MEMBEROF)

SEVERITY

CRITICAL

ENDPOINT

BINARY

securectrl.exe

/secserver

TESTED VERSIONS

9.4.505 / 9.4.513

This vulnerability is very similar to VULN 2. In this case, it is possible to inject inside LDAP queries through MEMBEROF "DESKTOP" parameter:

securecrtl.securecrtl_flagdesktop::flagdesktop
   …
   if (Operators.CompareString(text18, "MEMBEROF", false) == 0)
   {
       IL_490:
       num2 = 56;
       sMemberOf = text19;    // (1)
       IL_497:;
   }
   …
   if (!flag25)
   {
       IL_1FEA:
       num2 = 414;
       seldap.sGroup = sMemberOf;
       IL_1FF9:
      goto IL_1FFA;
   }
   …
   IL_1FFA:
   num2 = 416;
   string text23 = seldap.checkgroup();

     → SecurEnvoy.Common.seldap::checkgroup
       …
       this.server_loop(new ThreadStart(this.checkgroupthread));

        → SecurEnvoy.Common.seldap::checkgroupthread
           …
           string text2 = "(&(cn=" + this.sGroup + ")(objectClass=group))";    // (2)
           …
           directorySearcher.Filter = text2;
flagdesktop control flow

This time, variable sMemberOf is set (1) with user-controlled input that is then used to build the final LDAP query (2). An attacker controls this value by setting the parameter MEMBEROF within the "DESKTOP" message sent to the endpoint and can also leverage this issue to execute arbitrary queries.

Proof of concept

Optistream provides a simple Python script[3] to test your SecurEnvoy instance against the presence of these vulnerabilities. This proof of concept retrieves SecurEnvoy version through "DESKTOP" protocol and checks for blind LDAP injection.

SecurEnvoy vulnerable version

Indicators of compromise

There is no obvious way to detect the attack post-mortem.

Each "DESKTOP" request generates an authentication initiated by SecurEnvoy using the configured service account. Thus, you should investigate Windows event log looking for unsual 4624 events[4] to get an hint about suspect activities. Excessive amount of these events for this specific account may indicate exploitation attempt of LDAP injection or user enumeration.

You can also rely on SecurEnvoy internal logs (under "securectrl" process) in which could appear potentially malformed queries executed by an attacker:

"Log Viewer" - malformed LDAP queries

Moreover, we advise to enable SYSLOG or Windows events forwarding to your SIEM which is a feature offered by SecurEnvoy, that would make easier further investigation.

Conclusion

This blog entry underscores the critical importance of prioritizing the security of Internet-facing services. It is paramount to filter and block all non-essential exposed service endpoints, as they can introduce vulnerabilities. This example also highlights the need for proper network segmentation and limiting access to your assets[5].

Applying the principle of least privilege is crucial, as it can significantly mitigate the impact of an attack. In our case, the client's SecurEnvoy instance was using a highly privileged Active Directory domain account. Instead, it is advisable to use a dedicated service account (gMSA[6]) with limited rights, granting only the necessary permissions (you can often refer to vendors documentation for this kind of information).

In the absence of the aforementioned, implementation of an additional (security) solution may prove to weaken your overall security.

Timeline

Links

[1] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-37393
[2] https://securenvoy.com/wp-content/uploads/2024/06/Release-Notes-9.4.514-v2.pdf
[3] https://github.com/optistream/securenvoy-cve-2024-37393
[4] https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4624
[5]
Optistream - Zero Trust x Segmentation
[6] https://learn.microsoft.com/en-us/windows-server/security/group-managed-service-accounts/group-managed-service-accounts-overview