- Hi, it's good to be back.
Thank you all for being here.
Without doubt, Microsoft Exchange Server
is the most widely deployed mail solution
within governments and enterprises.
It is an integration of their
daily operations and security.
This January, we found a series
of vulnerabilities on Exchange Server to Microsoft,
and that gave us ProxyLogon.
If you are paying attention to the industry news,
you must have heard this then.
ProxyLogon may be the most severe
vulnerability in Exchange history ever.
However, as we went into a deep dive on ProxyLogon,
it came to us that it is not just a single bug,
but a whole new attack surface to help researchers
to uncover more vulnerabilities.
To unveil the beauty of this attack surface,
we will start from explaining the architecture,
analyzing the root cause,
and ending up with eight vulnerabilities we find.
By understanding the passives
of this new attack surface,
you won't be surprised
why we can pop out zero-days easily.
Let me introduce myself first, I'm Orange,
and now, the Principal Security Researcher at DEVCORE,
and a zero-day researcher,
and focusing on web and application security.
My job is to find out the most severe vulnerabilities
that can impact the work ahead of the bad guys,
and report them to the vendors directly.
Apart from that, I'm also a speaker, CTF player,
and bug bounty hunter.
I got several awards from my researches,
such as the Pwnie Awards,
and the Champion of Pwn2Own.
If you are interested,
welcome to follow my Twitter and blog.
Before I get started, here's the disclaimer.
All the CVS mentioned today
have been reported responsibly,
and have been patched by Microsoft.
So why were we targeting Exchange Server?
In terms of enterprise security,
mail servers are high-value assets
since they are the place to keep corporate confidentials.
With that being said,
if someone controls the mail server,
they can dominate the lifeline of the corporation.
Exchange Server is the most well-known
and important mail solution in the world.
With this in mind, Exchange has also
been the top target for nation
state hackers for a long time.
Based on our research, there are more
than 400,000 Exchange Servers exposed on the internet.
Every server represents a company.
You can imagine how severe it could be
when there's a critical vulnerability on Exchange Server.
Normally, I will review the existing papers
and bugs before starting a research.
Another whole Exchange history,
is there any interesting bug?
Of course, also known bugs
are best unknown attack vectors,
such as the deserialization or input validation.
There are several bugs that are worth mentioning.
The more special one is the arsenal
from Equation Group in 2017.
It's the only practical and public pre-auth RCE
in the Exchange history.
Unfortunately, the arsenal only works
on an ancient Exchange Server.
If the arsenal leak happened earlier,
it could lead to another nuclear-label crisis.
Another oh, I would say the most
surprising one is CVE 2020-0688.
The nature of this bug is due
to a hard-code crypto key.
It's 2020 now, such a common weakness
could still be find in a crucial software,
which inspired me to dig more
into the security of Exchange.
So what have we done?
We have reviewed the Exchange security
from the architectural levels
and find a new attack surface.
Through this new attack surface,
we uncovered eight vulnerabilities
and chained these bugs into three attacking exploits.
The first and the most famous one is ProxyLogon.
It's a pre-auth RCE.
The second one is ProxyOracle.
It's an exploit that can recover
any user's password in plain text format.
The last one is ProxyShell.
It's the exploit we demonstrate at Pwn2Own 2021.
It's also a pre-auth RCE.
I would like to highlight that all vulnerabilities
we uncovered here are logic bugs,
which means they could be reproduced
and exploited easily than any memory corruption bugs.
Here's my bug list.
The ones in red indicates the bug
is relate to the attack surface directly.
And others are the bugs which shared together.
For your references, there are other bugs
relate to this new attack surface.
You can see from this table,
and as nation state hackers are also playing that,
which means the attack surface we shared today
is a critical hit for Exchange Server.
Exchange is a very sophisticated application.
Before we cut to the chase,
let me introduce the architecture first.
Since 2000, Exchange has released
a new version every three years.
Whenever Exchange released a new version,
the architecture changed a lot
and becomes different.
The change of architecture and iterations
make it difficult to upgrade an Exchange Server.
In order to ensure the compatibility
between the new architecture and old ones,
several design steps were incurred
and led to the new attack surface we found.
So currently, we focused
on the Client Access Service, CAS.
CAS is a fundamental component in Exchange.
The official document indicates CAS
is a frontend that accept client
connections for all protocols,
and they're responsible for routing
and proxying connections.
CAS was prior repatched attention
to the whole attack service existed.
Because the CAS is located at a very early stage
of Exchange requires processing,
all bugs here are authentication-free.
So you can imagine how dangerous it is
when this fundamental service is vulnerable.
Here is the CAS architecture copied from the document.
As you can see, the left side is the clients.
No matter where the connection comes from,
either HTTP, POP3, IMAP, or SMTP,
CAS in the middle part proxies all connections
and proxy to the backend service on the right side.
The backend service will continue
to handle first, the business logics.
Because I specialize in web security,
so we focus on the web part.
The CAS web is built on Microsoft IIS.
As you can see, there are two websites inside of IIS.
The default website is the frontend we mentioned before,
and the Exchange backend is where the business logic is.
If you look at the configuration carefully,
you will notice the frontend is listening
on ports 80 and 443,
and the backend is listening on ports 81 and 444.
It should be note that the ports
are exposed on all interfaces.
You may sense something wrong here.
All the ports are open to all interfaces,
which means you can access the backend directly.
Wouldn't it be dangerous?
Please keep this question in mind,
and we will answer that later.
The CAS is composed of several IIS modules.
Applications in frontend include the ProxyModule,
which is responsible for passing all incoming requests,
applying protocol-specific settings,
and forwarding them to the backend.
As for the backend, applications include
a RehydrationModule, which is taking charge
of parsing frontend requests,
populating the client information back,
and continue the business logic.
So here is a question for you,
how did the frontend and backend
exchange the information?
They synchronize the information
and internal status by HTTP headers.
For client requests, it will first
be handled by the frontend,
and the request will be passed through several IIS modules,
such as the filter, validation, locking,
and alas, Proxy Module.
The Proxy Module then takes up a handler
based on the current application tests
such as the \OWA or \ECP.
The handler will do the proxy warp
and forward the request to the backend.
When the backend receives the request,
it passes the request to the RehydrationModule
to restore the original client state
and continue the business logics.
Our idea is simple.
Could we access the backend intentionally?
Since the Exchange synchronize the information
by HTTP headers, it seems like most
of the access control is done by the frontend.
If we can access the backend without restrictions,
maybe there are several internal API we can abuse.
We all know implementing a proxy isn't easy,
and the frontend seems like
a well-implemented HTTP client.
If there are some magic checks
to manipulate the context
between the frontend and backend, it must be found.
In order to abuse the context,
we have to know how the ProxyModule works first.
The ProxyRequestHandler is the most important
part of the frontend.
All handlers should inherit this class
to implement their methods
such as how to handle the client cookies or headers,
and how to proxy the client request to the backend.
We separate the methods into three section.
The first is Request, which will pass
and modify the client request.
Next is Proxy section, which will proxy
and send the HTTP request to the backend.
And the last section is Response.
This section will receive the response
from the backend and decide which header
or cookie should be sent back to the client.
Because this handler is important,
we will explain the methods one by one.
The first method of Request section
is CopyHeadersToServerRequest.
It will decide which HTTP header from the client
to be sent to the backend.
As we said, the frontend
and backend synchronize information
and internal status by HTTP headers.
Maybe you are thinking I could forge
the header to confuse something.
This is a nice try but unfortunately,
you can see here is a backlist in the method.
The frontend blocks several HTTP headers
which are used internally.
Please keep in mind that the header,
X-CommonAccessToken is an important one,
and we will learn this later.
The second is CopyCookiesToServerRequest.
The functionality is the same as the previous one,
but it copies cookies instead.
The last method of Request
is AddProtocolSpecificHeadersToServerRequest.
This method allows a handler
to apply customized protocol settings.
For example, if the frontend OWA
would like to pass information to the backend,
here is the class it can insert information to headers.
Besides the customized protocol settings,
the method also clones the user identity
to a new HTTP header.
The identity is the client authentication result in IIS,
also consisting of your security identifier.
This method serialize it to a string
and put it into the headers,
which will be forward to the backend later.
As of now, you note how the frontend
and backend synchronized your identity.
They do it by the header X-CommonAccessToken.
Once the request passing is done,
it will lead to the Proxy section.
The Proxy first uses the GetTargetBackEndServerUrl
to calculate the URL where the frontend should send to.
This method is also a bad request
and full of vulnerabilities.
We will discuss this later.
The second step of Proxy is CreateServerRequest,
which first initialize an HTTP client,
sets up the HTTP method and headers,
and forwards it to the backend.
We mentioned that POSTs in IIS are open to anyone
and this is dangerous.
So that's why Exchange has a mechanics
and to avoid the situation.
While the frontend is creating a request,
it will generate a Kerberos ticket
and put it in the Authorization header.
This header will be sent to the backend
along with the request.
So how does backend know which connection
is from a valid frontend?
It do it by verifying this Kerberos ticket.
We look into the GenerateKerberosAuthHeader
and know that the header is generated
with the HTTP SPN of the Exchange machine account.
If you observe the traffic
between the frontend and backend,
you will see two headers shown in the request.
One is the Authorization header,
which is the Kerberos ticket used
to indicate you are a valid frontend.
The other is the header X-CommonAccessToken.
It's a serialized token indicates your identity.
For example, if you log in with the name Orange,
the header is the serialized result
of your security identifier.
After sending the request to the backend,
the frontend receives the response
and enter the last section.
The Response section is similar to Request.
It checks the response from the backend
and decide which headers or cookies
are allowed to be sent back to the client.
Now, you understand how the frontend works,
let's move on to see how the backend processes
and populates the requests from the frontend.
The BackendRehydrationModule first used SYSTEM method
to check whether the incoming request
is authenticated or not.
It is the time to leverage
the Kerberos ticket the frontend generate.
By handing over this ticket,
the backend knows you are a valid frontend now.
The backend then call the method TryGetCommonAccessToken
to restore the user's identity from the frontend.
The method retrieves the header,
deserialize it back to the original access token,
and post in the httpContext object for later use.
So far, you learned how the frontend
and backend synchronized the user's identity
and how the header X-CommonAccessToken
plays an important role in the CAS architecture.
Since the method just checks
if the users are logged in or not,
it doesn't check the identity.
Here comes a question.
Can we authenticate as a normal user in the backend?
If you access the backend directly
and authenticate with a normal account,
we can specify what header values
in the header X-CommonAccessToken
and impersonate as any users.
The idea is good,
and actually, you can test
the IIS authentication of backend.
But there's one more checkpoint.
The method IsTokenSerializationAllowed
magnifies the current logged user
and raised a RehydrationException
if the checkpoint is failed.
It checks if you have a token serialization right.
By default, only the Exchange machine
account has this right.
So that's why the Kerberos ticket
generate by frontend can pass the checkpoint,
but you will fail even you are using a correct credential.
So here is a quick summary for you.
When there is the client request,
the frontend IIS first tries to authenticate the request.
If succeed, the frontend serialize the user identity
and adds it into the header X-CommonAccessToken.
The frontend then generates
a Kerberos ticket by its HTTP SPN
and posts it into the Authorization header.
It will forward these headers
along with the client request to the backend.
The backend also tries to authenticate
the request at the beginning.
The RehydrationModule will verify
whether the user have the right of token serialization.
Since we are using a Kerberos ticket
generate by the frontend we passed.
Lastly, the Rehydration restores the user identity
from the header X-CommonAccessToken
and continue the backend business logic.
So far, we briefly explained the communication
between the frontend and backend in short.
Let's start a hack.
Okay, the first exploit is ProxyLogon.
As introduced before, this may be the most
severe vulnerability in the Exchange history.
ProxyLogon is chained with two bugs to get the RCE.
One is an SSRF on the frontend,
and the other is an arbitrary file write
on the Control Panel of the backend.
So here is the ProxyLogon.
The bug is mainly locate at the Proxy
section in the frontend.
We mentioned that the frontend handler
calculates the backend URL
and forwards the request to that URL.
One of the handlers is in charge
of processing the static resources.
It will assign a backend target from the cookie.
You will figure out how simple
this bug is after learning the architecture.
The frontend trace the user-supplied cookie
as the domain name, and the domain name
will be concatenate as the backend URL.
We used a bit of passing tricks to enclose the URL
and forced the Exchange to fetch example.com.
The Exchange will then return
the whole response back to us.
So what is the root cause of this
arbitrary backend assignment?
As we mentioned that the Exchange Server
changed its architecture while releasing new versions.
This cookie is a quick solution for Exchange
to make the frontend in new architecture
to identify where the old backend is.
It looks like a design step
to adopt backward compatibility.
With the backend assignment,
we have a super SSRF that can control
almost all the requests and get all the responses.
The most impressive is that
it will generate a Kerberos ticket for us,
which means even when we are taking
a protected and domain-joined HTTP service,
we can still hack with the authentication
of Exchange machine account.
Thanks to the super SSRF,
we can leverage the internal API /proxylogon.ecp
to get a valid session to assess the Control Panel.
The API is also the reason
why we call a ProxyLogon.
As for the rest of the exploitation,
I believe there are already lots
of technical analyses out there.
We will skip it today for the consideration of time.
We will not do the demonstration today,
but if you are interested,
welcome to check the demo on our website.
Next, I will be sharing details about ProxyOracle.
Compared to ProxyLogon,
ProxyOracle is an interesting exploit
with a different approach.
ProxyOracle will allow the attacker
to recover the victim's plain text password
simply by leading them to a malicious link.
We used a cross-site scripting
and padding oracle to complete the exploit.
First, we would like to explain how the OWA
or ECP authenticate users.
If the negative IIS authentication is used,
an ugly prompt will pop out,
asking you to enter the password
instead of this fancy interface,
which means Exchange is using a certain mechanics
to execute the transformation
between the credentials and cookies.
So let's take a look at how this fancy interface
is working with the original architecture.
Let's get back to the IIS architecture.
All the OWA and ECP login mechanics
are done by the Form-Based Authentication module.
The FBA is an authentication manager
prior to the Exchange frontend
and responsible for converting
the username and password into cookies,
or translating cookies to the original credential pairs.
The implementation store your username
and password in cookies directly.
Of course, the cookie is encrypted
to avoid bad guys catching your password
in plain text on the fly.
If you read the login traffic carefully,
you will see several cookies,
which stand for your identity.
For the later mail configuration,
you have to attach cookies to identify who you are,
but not all cookies,
there are five important ones
with the prefix cadata.
You can see from the screen,
the cadata contains your encrypted username and password.
Here is the pseudocode for the encryption logic.
Exchange generates two random strings
as the IV and Key for every session.
The IV and Key will be sent
and stored on the client's side.
However, to avoid someone stealing the cookies
and decrypting it with the IV and key,
Exchange uses RSA to encrypt
with its private key again before sending.
The Exchange then uses the AES
to encrypt your encoded credential with the IV and Key
and put the result into the cookies.
And yes, you can find padding oracle here.
Exchange texts the CBC of its padding mode.
If you are familiar with cryptography,
you must know that CBC is vulnerable
to the padding oracle attack.
The Exchange implementation catches
the padding error and returns immediately.
When the login process fails,
Exchange redirects the HTTP back
to the login patch with an error code.
Due to the return, we have an oracle here.
If the encryption fails, the error code is zero,
which stands for null.
And if we corrupt the cyber attacks successfully,
the Exchange will try to log in
with the corrupted credential pair.
At this moment, the result must be a failure
and the error code is two,
which stands for the invalid credentials.
By differing from the error number,
we have an oracle to recover the plain text.
Now, we know we can decrypt any cookies
with the padding oracle
but the problem is how to get
the cookies from the victim?
In order to get a cookie on clients,
we uncover a cross-site scripting to chain together.
But it comes up with another problem
being Exchange-authenticated cookies
are protected by HttpOnly,
so we can't access the cookies by JavaScript.
So how can we do?
Since we can execute arbitrary
JavaScript on client side,
why don't we just insert an SSRF cookie,
which is used in ProxyLogon?
Why don't we add a cookie to the browser?
We can sniff and take over
all the user's web requests.
All we need to do is to sit on our server
and wait for the cookies to come back.
I will elaborate the process further.
We first send a malicious link to the victim.
And once the victim triggers our cross-site scripting,
we insert the SSRF cookie to pretend
we are the backend of Exchange.
And then the Exchange Server becomes a proxy
between the victim and us,
we will take over all the traffic to bypass
the HttpOnly to get the encrypted cookies.
Okay, the demo part.
First, we have the victim,
and we pass his mail address to our exploit.
The exploit first send a malicious link to the target.
And once the victim triggers our cross-site scripting,
we insert a SSRF cookie and wait for the connection
back to obtain the encrypted cookies.
Okay, we got a connection.
We can now decrypt the blocks by padding oracle.
It should be note that all the decryption
could be done without the cross-site scripting.
Even the user close the browser,
we can still recover the password.
With a little bit waiting,
we recovered the password in plain text successfully.
The last exploit I will share today is ProxyShell.
This is the exploit we demonstrate at Pwn2Own 2021.
The result of ProxyShell
is the same as ProxyLogon.
An unauthenticated attacker can execute
arbitrary commands on the Exchange Server.
But the exploit chain is different.
ProxyShell is chained with an ACL bypass in the frontend,
an elevation of privilege
in the Exchange PowerShell backend,
and an arbitrary file-write to get RCE.
So where is the ProxyShell?
The first pre-auth path is also
a GET at the backend URL calculation.
ProxyShell begins with a path confusion.
Exchange has a feature called Explicit Logon feature.
This feature is used to describe
another user's mailbox or calendar
in a new browser window.
Of course, the displayed mailbox
must have to be configured
with permission to publish first.
In order to open with a single GET request,
the URL format must be simple,
and the mailbox address must be include in the URL
such as the highlight part in the slide.
The Exchange normalize this special URL
and reroutes it to the existing handlers.
Of course, the path is not the only way
to specify the mailbox address.
We find that a special cast in the Autodiscover handler,
Exchange will consider address
from the current string
if the path.EndsWith /autodiscover.json.
After getting the address,
the handler tries to normalize the URL.
You'll see that Exchange won't conduct
too much checking on the pattern
of removing mailbox address,
which led us to use the substring
to erase any part of the URL.
As you could see from the slide,
this is the URL we will be visiting.
And this is the mailbox address
we use the query string to specify.
And here is the part will be removed
from Exchange according to our pattern
with the address.
This is the actual URL
the request will be sent to the backend.
But for now, we can access any Exchange backend again.
Also, this block is not as powerful
as the SSRF in ProxyLogon.
It's sufficient to assess arbitrary backends.
We tries to access the API in the path
to identify our privilege.
From the screenshot, you could see that
we could access the backend
with the Exchange instant privilege again.
Here comes the post-exploitation part.
The approach of original ProxyLogon fails
due to some Exchange in-depth protections.
So we have to discover a new approach.
Now, let's turn the focus to Exchange PowerShell Remoting,
a feature for Exchange automations.
Through the defined PowerShell commands,
users can read mail, send mail,
and even configure settings by command lines.
The Exchange PowerShell implementation
is built upon the PowerShell API.
By calling the API,
Exchange could realize a PowerShell server
and uses the Runspace to name it
and isolate the command execution.
All the operations are based on the WinRM protocol.
It should be note that also we can access
the PowerShell backend directly.
We can still interact with it
because we are the SYSTEM.
We will fail the business logic
since there is no mailbox for the SYSTEM user.
We also can forge our identity
by the header X-CommonAccessToken
due to the blacklist in the frontend.
So what should I do?
We dive into the PowerShell server implementation
and find a piece of code that
extracts the access token from the URL.
The code is leading after the IIS backend authentication
and before the Rehydration.
It checks if there is no X-CommonAccessToken header,
the code will call out another method
to get the access token from the URL.
The CommonAccessTokenFromUrl is a short method
and retrieves the value of X-Rps-CAT from query string,
and then deserialize it back to the access token.
As for now, we have an elevation of privilege
because we can access the PowerShell backend
and specify the access token directly.
The intention of this operation
is to be a quick proxy for internal
Exchange PowerShell communication.
By abusing this feature,
we can impersonate as any user.
Here, we use the EOP to downgrade ourself
from the SYSTEM result mailbox to Exchange Admin.
I can now execute arbitrary Exchange PowerShell
commands as Admin, and then?
The last piece of the puzzle
is to find a post-auth RCE
to chain everything together.
Because we are adding, and there are hundreds
of Exchange PowerShell commands out there,
it's easy to find a post-auth bug.
We abused the command New-MailboxExportRequest
to explore the user's mailbox
into the WebLoad to be our WebShell.
Now, we can create files on arbitrary tests.
The next problem is how to embed
our malicious payload into this file.
It's also easy.
We can deliver our payload by mail.
However, the exploited file is encoded.
By reading the Microsoft document,
we learned it's in PST format
and the encoding is just a simple table matrix.
We can just encode the payload before sending out.
While the server tries to save
and encode our payload,
it turns into the original malicious code.
Let's check everything together.
We first deliver our encoded WebShell
to the target mailbox,
and then launch the Windows PowerShell client
to connect to our proxy server.
We use a proxy server because we have to modify
the WinRM protocol to rewrite the path
to the vulnerable Autodiscover handler,
which will eventually trigger the path confusion bug
and add an access token to the query string.
Once the station has been established,
we can execute the PowerShell command
to grant ourself the mailbox export log
and involve the mailbox exploiting.
And the next step is to enjoy the shell.
Let's go to the demonstration.
So this is the Exchange Server,
and we run our exploit.
The exploit first sent our
encoded payload to the mailbox
and launched the PowerShell
to establish the WinRM connection.
We used a proxy server to rewrite
the traffic to implement our exploit.
Okay, we see our shell is dropped.
And we are the SYSTEM.
Let's talk about mitigations.
Since it's an architectural problem,
it's hard to mitigate the attack surface
with one single action.
All you can do is keep your Exchange Server up to date
and with the support of a firewall
or ACL to not externally facing the internet.
Microsoft has enhanced the CAS architecture in April.
The authentication part of this attack surface
has been reduced in the patch.
So if you are lazy,
please update the April patch at least.
And if you are super lazy,
maybe you can give a shot at the Office 365.
Okay, conclusion, modern problems
require modern solutions.
It's hard to find traditional bugs
in modern architecture.
Sometimes comprehending the architecture
from a higher point of view can help you
fight new, interesting bugs.
The CAS is still a good attack surface
although Microsoft has patched it in April.
However, in fact, we still find a few bugs
after the April patch.
But since the authentication part
of this attack surface is reduced,
the result may not be as powerful
as before due to the lack of pre-auth bugs.
Lastly, the Exchange is still a treasure
waiting for you to find bugs.
As mentioned, even in 2020,
a hard-code crypto key can still
be find in Exchange Server.
I can assure you that Microsoft will fix
more Exchange vulnerabilities in the future.
But here comes the spoiler alert.
Even if you find a super critical vulnerability
like ProxyLogon, Microsoft will not reward
you any bounty because the Exchange Server
on-premise is out of scope.
So is it was fun hunting bugs on Exchange Server?
You tell me.
This is the end of my presentation.
If you have any questions,
here's my contact information.
By the way, I will post
a detailed article on my blog.
Please look forward to that.
Thank you again for being here, thanks.