Some notes about Microsoft Exchange Deserialization RCE (CVE-2021–42321)

INTRO

It’s been several months since our last story about ProxyShell Exploit and recently Exchange was pwned again at Tianfu Cup 2021. We’re very excited about that Exploit and we’re waiting for Tuesday Patch of MS Exchange this month to analyse it.

https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-42321
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-42321
https://www.catalog.update.microsoft.com/Search.aspx?q=Exchange%202016

THE SINK

We noticed that some files were removed

Microsoft.Exchange.Compliance.Serialization.Formatters.TypedBinaryFormatter
Microsoft.Exchange.Diagnostics.ExchangeBinaryFormatterFactory.CreateBinaryFormatter()
  • strictMode = false
  • allowList = System.DelegateSerializationHolder
  • allowedGenerics = null
ChainedSerializationBinder.BindToType()
ChainedSerializationBinder.ValidateTypeToDeserialize()
  • If the strictMode is False and our class is not in allow list, and in blacklist , Exchange will throw InvalidOperationException
  • In this function, it only catches BlockedDeserializationException so InvalidOperationException will not be caught, so if Exchange through InvalidOperationException our deserialization chain will be broken
  • If there’s a BlockedDeserializationException while ValidateTypeToDeserialize() was thrown, it will be caught in catch block but Exchange only throws that Exception when the value of the flag is True, but remembered that the strictMode value was passed to ChainedSerializationBinder is always False ! So there’s Exchange will catch BlockedDeserializationException safely and Exchange didn’t affect our Deserialization can continue without crashing.
System.Security.Claims.ClaimsPrincipal.OnDeserializedMethod()
System.Security.Claims.ClaimsPrincipal.DeserializeIdentities()
BinaryFormatter.Deserialize()

THE SOURCE

With Dnspy we tracing back to find where we can trigger deserialization

CreateUserConfiguration.Execute()
UserConfigurationCommandBase.SetProperties()
UserConfigurationCommandBase.SetStream()
UserConfigurationCommandBase.SetProperties()
UserConfigurationCommandBase.SetStream()
sample request for setting BinaryData
sample request for GetClientAccessToken

FULL EXPLOIT

We finally achieve post-auth RCE:

  1. Create UserConfiguration with BinaryData as our Gadget Chain
  2. Request to EWS for GetClientAccessToken to trigger the Deserialization
  • We can embed any ysoserial.net gadget chain into System.Security.Claims.ClaimsPrincipal to trigger 2nd Deserialization
  • Or we can use directly use TypeConfusedDelegate Chain (This chain is not in the blacklist of ChainedSerializationBinder and I don’t know why :> )

IMPROVEMENT

We already can pop calc on our Lab environment but how about the actual environment with up to date Windows Defender?

This is what we got :)
A snippet of code to eval JScript
We’ve been laughing for hours while making this meme
This is how we call Process.Start()
from TypeConfusedDelegate -> XamlReader.Parse()

Final Thought

This exploit only work for

  • Microsoft Exchange 2019 CU10, 11
  • Microsoft Exchange 2016 CU21, 22

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store