Attacker Value
Very High
(1 user assessed)
Exploitability
Moderate
(1 user assessed)
User Interaction
Required
Privileges Required
None
Attack Vector
Local
3

CVE-2021-26857

Disclosure Date: March 03, 2021
Exploited in the Wild
Add MITRE ATT&CK tactics and techniques that apply to this CVE.

Description

Microsoft Exchange Server Remote Code Execution Vulnerability This CVE ID is unique from CVE-2021-26412, CVE-2021-26854, CVE-2021-26855, CVE-2021-26858, CVE-2021-27065, CVE-2021-27078.

Add Assessment

3
Ratings
Technical Analysis

As per Microsoft’s blog post on Exchange Server 0day use by the HAFNIUM actors, CVE-2021-26857 is a deserialization vulnerability in Exchange Server’s Unified Messaging (voicemail) service. Exploiting the vulnerability reportedly requires admin access or chaining with another vuln (likely CVE-2021-26855), but successful exploitation results in RCE as the SYSTEM account. This vulnerability would ideally be combined with an auth bypass, which CVE-2021-26855 may very well provide.

I took a look at CVE-2021-26857 last night and came up with the following patch diff:

--- exchange.unpatched/Microsoft.Exchange.UM.UMCore/UMCore/PipelineContext.cs	2021-03-02 19:54:18.000000000 -0600
+++ exchange.patched/Microsoft.Exchange.UM.UMCore/UMCore/PipelineContext.cs	2021-03-02 19:55:19.000000000 -0600
@@ -1,742 +1,886 @@
 using System;
+using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
+using System.Runtime.Serialization;
+using Microsoft.Exchange.Compliance.Serialization.Formatters;
+using Microsoft.Exchange.Data;
+using Microsoft.Exchange.Data.Common;
 using Microsoft.Exchange.Data.Directory;
 using Microsoft.Exchange.Data.Directory.Recipient;
 using Microsoft.Exchange.Data.Directory.SystemConfiguration;
 using Microsoft.Exchange.Data.Storage;
 using Microsoft.Exchange.Diagnostics;
 using Microsoft.Exchange.Diagnostics.Components.UnifiedMessaging;
 using Microsoft.Exchange.ExchangeSystem;
 using Microsoft.Exchange.TextProcessing.Boomerang;
 using Microsoft.Exchange.UM.UMCommon;
+using Microsoft.Mapi;

 namespace Microsoft.Exchange.UM.UMCore
 {
 	internal abstract class PipelineContext : DisposableBase, IUMCreateMessage
 	{
 		internal PipelineContext()
 		{
 		}

 		internal PipelineContext(SubmissionHelper helper)
 		{
 			bool flag = false;
 			try
 			{
 				this.helper = helper;
 				this.cultureInfo = new CultureInfo(helper.CultureInfo);
 				flag = true;
 			}
 			finally
 			{
 				if (!flag)
 				{
 					this.Dispose();
 				}
 			}
 		}

 		public MessageItem MessageToSubmit
 		{
 			get
 			{
 				return this.messageToSubmit;
 			}
 			protected set
 			{
 				this.messageToSubmit = value;
 			}
 		}

 		public string MessageID
 		{
 			get
 			{
 				return this.messageID;
 			}
 			protected set
 			{
 				this.messageID = value;
 			}
 		}

 		internal abstract Pipeline Pipeline { get; }

 		internal Microsoft.Exchange.UM.UMCommon.PhoneNumber CallerId
 		{
 			get
 			{
 				return this.helper.CallerId;
 			}
 		}

 		internal Guid TenantGuid
 		{
 			get
 			{
 				return this.helper.TenantGuid;
 			}
 		}

 		internal int ProcessedCount
 		{
 			get
 			{
 				return this.processedCount;
 			}
 		}

 		internal ExDateTime SentTime
 		{
 			get
 			{
 				return this.sentTime;
 			}
 			set
 			{
 				this.sentTime = value;
 			}
 		}

 		internal CultureInfo CultureInfo
 		{
 			get
 			{
 				return this.cultureInfo;
 			}
 		}

 		protected internal string HeaderFileName
 		{
 			get
 			{
 				if (string.IsNullOrEmpty(this.headerFileName))
 				{
 					Guid guid = Guid.NewGuid();
 					this.headerFileName = Path.Combine(Utils.VoiceMailFilePath, guid.ToString() + ".txt");
 				}
 				return this.headerFileName;
 			}
 			protected set
 			{
 				this.headerFileName = value;
 			}
 		}

 		protected internal string CallerAddress
 		{
 			get
 			{
 				return this.helper.CallerAddress;
 			}
 			protected set
 			{
 				this.helper.CallerAddress = value;
 			}
 		}

 		protected internal string CallerIdDisplayName
 		{
 			get
 			{
 				return this.helper.CallerIdDisplayName;
 			}
 			protected set
 			{
 				this.helper.CallerIdDisplayName = value;
 			}
 		}

 		protected internal string MessageType
 		{
 			internal get
 			{
 				return this.messageType;
 			}
 			set
 			{
 				this.messageType = value;
 			}
 		}

 		public virtual void PrepareUnProtectedMessage()
 		{
 			CallIdTracer.TraceDebug(ExTraceGlobals.VoiceMailTracer, this.GetHashCode(), "PipelineContext:PrepareUnProtectedMessage.", Array.Empty<object>());
 			using (DisposeGuard disposeGuard = default(DisposeGuard))
 			{
 				this.messageToSubmit = MessageItem.CreateInMemory(StoreObjectSchema.ContentConversionProperties);
 				disposeGuard.Add<MessageItem>(this.messageToSubmit);
 				this.SetMessageProperties();
 				disposeGuard.Success();
 			}
 		}

 		public virtual void PrepareProtectedMessage()
 		{
 			throw new InvalidOperationException();
 		}

 		public virtual void PrepareNDRForFailureToGenerateProtectedMessage()
 		{
 			throw new InvalidOperationException();
 		}

 		public virtual PipelineDispatcher.WIThrottleData GetThrottlingData()
 		{
 			return new PipelineDispatcher.WIThrottleData
 			{
 				Key = this.GetMailboxServerId(),
 				RecipientId = this.GetRecipientIdForThrottling(),
 				WorkItemType = PipelineDispatcher.ThrottledWorkItemType.NonCDRWorkItem
 			};
 		}

 		public virtual void PostCompletion()
 		{
 			CallIdTracer.TraceDebug(ExTraceGlobals.VoiceMailTracer, 0, "PipelineContext - Deleting header file '{0}'", new object[]
 			{
 				this.headerFileName
 			});
 			Util.TryDeleteFile(this.headerFileName);
 		}

 		internal static PipelineContext FromHeaderFile(string headerFile)
 		{
 			PipelineContext pipelineContext = null;
 			PipelineContext result;
 			try
 			{
 				ContactInfo contactInfo = null;
 				string text = null;
 				int num = 0;
 				ExDateTime exDateTime = default(ExDateTime);
 				string text2 = null;
 				SubmissionHelper submissionHelper = new SubmissionHelper();
 				uint num2;
 				using (StreamReader streamReader = File.OpenText(headerFile))
 				{
 					string text3;
 					while ((text3 = streamReader.ReadLine()) != null)
 					{
 						string[] array = text3.Split(" : ".ToCharArray(), 2, StringSplitOptions.RemoveEmptyEntries);
 						if (array != null && array.Length == 2)
 						{
 							string text4 = array[0];
 							num2 = <PrivateImplementationDetails>.ComputeStringHash(text4);
 							if (num2 <= 872212143U)
 							{
 								if (num2 <= 134404218U)
 								{
 									if (num2 != 77294025U)
 									{
 										if (num2 != 111122938U)
 										{
-											if (num2 == 134404218U)
+											if (num2 != 134404218U)
 											{
-												if (text4 == "ProcessedCount")
-												{
-													num = Convert.ToInt32(array[1], CultureInfo.InvariantCulture) + 1;
-													continue;
-												}
+												goto IL_409;
+											}
+											if (!(text4 == "ProcessedCount"))
+											{
+												goto IL_409;
 											}
+											num = Convert.ToInt32(array[1], CultureInfo.InvariantCulture) + 1;
+											continue;
 										}
-										else if (text4 == "RecipientObjectGuid")
+										else
 										{
+											if (!(text4 == "RecipientObjectGuid"))
+											{
+												goto IL_409;
+											}
 											submissionHelper.RecipientObjectGuid = new Guid(array[1]);
 											continue;
 										}
 									}
-									else if (text4 == "CallerNAme")
+									else
 									{
+										if (!(text4 == "CallerNAme"))
+										{
+											goto IL_409;
+										}
 										submissionHelper.CallerName = array[1];
 										continue;
 									}
 								}
 								else if (num2 <= 507978139U)
 								{
 									if (num2 != 152414519U)
 									{
-										if (num2 == 507978139U)
+										if (num2 != 507978139U)
 										{
-											if (text4 == "RecipientName")
-											{
-												submissionHelper.RecipientName = array[1];
-												continue;
-											}
+											goto IL_409;
 										}
+										if (!(text4 == "RecipientName"))
+										{
+											goto IL_409;
+										}
+										submissionHelper.RecipientName = array[1];
+										continue;
 									}
-									else if (text4 == "ContactInfo")
+									else
 									{
-										contactInfo = (CommonUtil.Base64Deserialize(array[1]) as ContactInfo);
-										continue;
+										if (!(text4 == "ContactInfo"))
+										{
+											goto IL_409;
+										}
+										Exception ex = null;
+										try
+										{
+											try
+											{
+												using (MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(array[1])))
+												{
+													contactInfo = (ContactInfo)TypedBinaryFormatter.DeserializeObject(memoryStream, PipelineContext.contactInfoDeserializationAllowList, null, true);
+												}
+											}
+											catch (ArgumentNullException ex)
+											{
+											}
+											catch (SerializationException ex)
+											{
+											}
+											catch (Exception ex)
+											{
+											}
+											continue;
+										}
+										finally
+										{
+											if (ex != null)
+											{
+												CallIdTracer.TraceDebug(ExTraceGlobals.VoiceMailTracer, 0, "Failed to get contactInfo from header file {0} with Error={1}", new object[]
+												{
+													headerFile,
+													ex
+												});
+											}
+										}
 									}
 								}
 								else if (num2 != 707084238U)
 								{
-									if (num2 == 872212143U)
+									if (num2 != 872212143U)
 									{
-										if (text4 == "CallerId")
-										{
-											submissionHelper.CallerId = Microsoft.Exchange.UM.UMCommon.PhoneNumber.Parse(array[1]);
-											continue;
-										}
+										goto IL_409;
 									}
+									if (!(text4 == "CallerId"))
+									{
+										goto IL_409;
+									}
+									submissionHelper.CallerId = Microsoft.Exchange.UM.UMCommon.PhoneNumber.Parse(array[1]);
+									continue;
 								}
-								else if (text4 == "SentTime")
+								else
 								{
+									if (!(text4 == "SentTime"))
+									{
+										goto IL_409;
+									}
 									DateTime dateTime = Convert.ToDateTime(array[1], CultureInfo.InvariantCulture);
 									exDateTime = new ExDateTime(ExTimeZone.CurrentTimeZone, dateTime);
 									continue;
 								}
 							}
 							else if (num2 <= 2593661420U)
 							{
 								if (num2 <= 1526417836U)
 								{
 									if (num2 != 978885386U)
 									{
-										if (num2 == 1526417836U)
+										if (num2 != 1526417836U)
 										{
-											if (text4 == "MessageType")
-											{
-												text = array[1];
-												continue;
-											}
+											goto IL_409;
+										}
+										if (!(text4 == "MessageType"))
+										{
+											goto IL_409;
 										}
+										text = array[1];
+										continue;
 									}
-									else if (text4 == "CallerAddress")
+									else
 									{
+										if (!(text4 == "CallerAddress"))
+										{
+											goto IL_409;
+										}
 										submissionHelper.CallerAddress = array[1];
 										continue;
 									}
 								}
 								else if (num2 != 1850847732U)
 								{
-									if (num2 == 2593661420U)
+									if (num2 != 2593661420U)
 									{
-										if (text4 == "CallId")
-										{
-											submissionHelper.CallId = array[1];
-											continue;
-										}
+										goto IL_409;
 									}
+									if (!(text4 == "CallId"))
+									{
+										goto IL_409;
+									}
+									submissionHelper.CallId = array[1];
+									continue;
 								}
-								else if (text4 == "CallerIdDisplayName")
+								else
 								{
+									if (!(text4 == "CallerIdDisplayName"))
+									{
+										goto IL_409;
+									}
 									submissionHelper.CallerIdDisplayName = array[1];
 									continue;
 								}
 							}
 							else if (num2 <= 3342616108U)
 							{
 								if (num2 != 2975106116U)
 								{
-									if (num2 == 3342616108U)
+									if (num2 != 3342616108U)
 									{
-										if (text4 == "TenantGuid")
-										{
-											submissionHelper.TenantGuid = new Guid(array[1]);
-											continue;
-										}
+										goto IL_409;
 									}
+									if (!(text4 == "TenantGuid"))
+									{
+										goto IL_409;
+									}
+									submissionHelper.TenantGuid = new Guid(array[1]);
+									continue;
 								}
-								else if (text4 == "SenderAddress")
+								else
 								{
+									if (!(text4 == "SenderAddress"))
+									{
+										goto IL_409;
+									}
 									string text5 = array[1];
 									continue;
 								}
 							}
 							else if (num2 != 3581765001U)
 							{
-								if (num2 == 4186841001U)
+								if (num2 != 4186841001U)
 								{
-									if (text4 == "CultureInfo")
-									{
-										submissionHelper.CultureInfo = array[1];
-										continue;
-									}
+									goto IL_409;
+								}
+								if (!(text4 == "CultureInfo"))
+								{
+									goto IL_409;
 								}
+								submissionHelper.CultureInfo = array[1];
+								continue;
 							}
-							else if (text4 == "MessageID")
+							else if (!(text4 == "MessageID"))
 							{
-								text2 = array[1];
-								continue;
+								goto IL_409;
 							}
+							text2 = array[1];
+							continue;
+							IL_409:
 							submissionHelper.CustomHeaders[array[0]] = array[1];
 						}
 					}
 				}
 				num2 = <PrivateImplementationDetails>.ComputeStringHash(text);
 				if (num2 <= 894870128U)
 				{
 					if (num2 <= 360985808U)
 					{
 						if (num2 != 356120169U)
 						{
 							if (num2 == 360985808U)
 							{
 								if (text == "Fax")
 								{
 									pipelineContext = new FaxPipelineContext(submissionHelper);
-									goto IL_62E;
+									goto IL_694;
 								}
 							}
 						}
 						else if (text == "IncomingCallLog")
 						{
 							pipelineContext = new IncomingCallLogPipelineContext(submissionHelper);
-							goto IL_62E;
+							goto IL_694;
 						}
 					}
 					else if (num2 != 438908515U)
 					{
 						if (num2 != 466919760U)
 						{
 							if (num2 == 894870128U)
 							{
 								if (text == "CDR")
 								{
 									pipelineContext = CDRPipelineContext.Deserialize((string)submissionHelper.CustomHeaders["CDRData"]);
-									goto IL_62E;
+									goto IL_694;
 								}
 							}
 						}
 						else if (text == "MissedCall")
 						{
 							pipelineContext = new MissedCallPipelineContext(submissionHelper);
-							goto IL_62E;
+							goto IL_694;
 						}
 					}
 					else if (text == "OCSNotification")
 					{
 						pipelineContext = OCSPipelineContext.Deserialize((string)submissionHelper.CustomHeaders["OCSNotificationData"]);
 						text2 = pipelineContext.messageID;
 						exDateTime = pipelineContext.sentTime;
-						goto IL_62E;
+						goto IL_694;
 					}
 				}
 				else if (num2 <= 1086454342U)
 				{
 					if (num2 != 995233564U)
 					{
 						if (num2 == 1086454342U)
 						{
 							if (text == "XSOVoiceMail")
 							{
 								pipelineContext = new XSOVoiceMessagePipelineContext(submissionHelper);
-								goto IL_62E;
+								goto IL_694;
 							}
 						}
 					}
 					else if (text == "PartnerTranscriptionRequest")
 					{
 						pipelineContext = new PartnerTranscriptionRequestPipelineContext(submissionHelper);
-						goto IL_62E;
+						goto IL_694;
 					}
 				}
 				else if (num2 != 1356218075U)
 				{
 					if (num2 != 2525024257U)
 					{
 						if (num2 == 3974407582U)
 						{
 							if (text == "SMTPVoiceMail")
 							{
 								if (num < PipelineWorkItem.ProcessedCountMax - 1)
 								{
 									pipelineContext = new VoiceMessagePipelineContext(submissionHelper);
-									goto IL_62E;
+									goto IL_694;
 								}
 								pipelineContext = new MissedCallPipelineContext(submissionHelper);
-								goto IL_62E;
+								goto IL_694;
 							}
 						}
 					}
 					else if (text == "HealthCheck")
 					{
 						pipelineContext = new HealthCheckPipelineContext(Path.GetFileNameWithoutExtension(headerFile));
-						goto IL_62E;
+						goto IL_694;
 					}
 				}
 				else if (text == "OutgoingCallLog")
 				{
 					pipelineContext = new OutgoingCallLogPipelineContext(submissionHelper);
-					goto IL_62E;
+					goto IL_694;
 				}
 				throw new HeaderFileArgumentInvalidException(string.Format(CultureInfo.InvariantCulture, "{0}: {1}", "MessageType", text));
-				IL_62E:
+				IL_694:
 				if (text2 == null)
 				{
 					text2 = Guid.NewGuid().ToString();
 					exDateTime = ExDateTime.Now;
 				}
 				pipelineContext.HeaderFileName = headerFile;
 				pipelineContext.processedCount = num;
 				if (contactInfo != null)
 				{
 					IUMResolveCaller iumresolveCaller = pipelineContext as IUMResolveCaller;
 					if (iumresolveCaller != null)
 					{
 						iumresolveCaller.ContactInfo = contactInfo;
 					}
 				}
 				pipelineContext.sentTime = exDateTime;
 				pipelineContext.messageID = text2;
 				pipelineContext.WriteHeaderFile(headerFile);
 				result = pipelineContext;
 			}
-			catch (IOException ex)
+			catch (IOException ex2)
 			{
 				CallIdTracer.TraceDebug(ExTraceGlobals.VoiceMailTracer, 0, "Failed to parse the header file {0} because its not closed by thread creating the file.  Error={1}", new object[]
 				{
 					headerFile,
-					ex
+					ex2
 				});
 				if (pipelineContext != null)
 				{
 					pipelineContext.Dispose();
 					pipelineContext = null;
 				}
 				result = null;
 			}
-			catch (InvalidObjectGuidException ex2)
+			catch (InvalidObjectGuidException ex3)
 			{
 				CallIdTracer.TraceWarning(ExTraceGlobals.VoiceMailTracer, 0, "Couldn't find the recipient for this message. Error={0}", new object[]
 				{
-					ex2
+					ex3
 				});
 				if (pipelineContext != null)
 				{
 					pipelineContext.Dispose();
 					pipelineContext = null;
 				}
 				throw;
 			}
-			catch (InvalidTenantGuidException ex3)
+			catch (InvalidTenantGuidException ex4)
 			{
 				CallIdTracer.TraceWarning(ExTraceGlobals.VoiceMailTracer, 0, "Couldn't find the tenant for this message. Error={0}", new object[]
 				{
-					ex3
+					ex4
 				});
 				if (pipelineContext != null)
 				{
 					pipelineContext.Dispose();
 					pipelineContext = null;
 				}
 				throw;
 			}
-			catch (NonUniqueRecipientException ex4)
+			catch (NonUniqueRecipientException ex5)
 			{
 				CallIdTracer.TraceWarning(ExTraceGlobals.VoiceMailTracer, 0, "Multiple objects found for the recipient. Error={0}", new object[]
 				{
-					ex4
+					ex5
 				});
 				if (pipelineContext != null)
 				{
 					pipelineContext.Dispose();
 					pipelineContext = null;
 				}
 				throw;
 			}
 			return result;
 		}

 		internal abstract void WriteCustomHeaderFields(StreamWriter headerStream);

 		public abstract string GetMailboxServerId();

 		public abstract string GetRecipientIdForThrottling();

 		internal virtual void SaveMessage()
 		{
 			this.WriteHeaderFile(this.HeaderFileName);
 		}

 		protected override void InternalDispose(bool disposing)
 		{
 			if (disposing)
 			{
 				CallIdTracer.TraceDebug(ExTraceGlobals.VoiceMailTracer, this.GetHashCode(), "PipelineContext.Dispose() called", Array.Empty<object>());
 			}
 		}

 		protected override DisposeTracker InternalGetDisposeTracker()
 		{
 			return DisposeTracker.Get<PipelineContext>(this);
 		}

 		protected virtual void SetMessageProperties()
 		{
 			IUMResolveCaller iumresolveCaller = this as IUMResolveCaller;
 			if (iumresolveCaller != null)
 			{
 				ExAssert.RetailAssert(iumresolveCaller.ContactInfo != null, "ResolveCallerStage should always set the ContactInfo.");
 				UMSubscriber umsubscriber = ((IUMCAMessage)this).CAMessageRecipient as UMSubscriber;
 				UMDialPlan dialPlan = (umsubscriber != null) ? umsubscriber.DialPlan : null;
 				Microsoft.Exchange.UM.UMCommon.PhoneNumber pstnCallbackTelephoneNumber = this.CallerId.GetPstnCallbackTelephoneNumber(iumresolveCaller.ContactInfo, dialPlan);
 				this.messageToSubmit.From = iumresolveCaller.ContactInfo.CreateParticipant(pstnCallbackTelephoneNumber, this.CultureInfo);
 				XsoUtil.SetVoiceMessageSenderProperties(this.messageToSubmit, iumresolveCaller.ContactInfo, dialPlan, this.CallerId);
 				this.messageToSubmit.InternetMessageId = BoomerangHelper.FormatInternetMessageId(this.MessageID, Utils.GetHostFqdn());
 				this.messageToSubmit[ItemSchema.SentTime] = this.SentTime;
 			}
 			this.messageToSubmit.AutoResponseSuppress = AutoResponseSuppress.All;
 			this.messageToSubmit[MessageItemSchema.CallId] = this.helper.CallId;
 			IUMCAMessage iumcamessage = this as IUMCAMessage;
 			if (iumcamessage != null)
 			{
 				this.MessageToSubmit.Recipients.Add(new Participant(iumcamessage.CAMessageRecipient.ADRecipient));
 				IADSystemConfigurationLookup iadsystemConfigurationLookup = ADSystemConfigurationLookupFactory.CreateFromOrganizationId(iumcamessage.CAMessageRecipient.ADRecipient.OrganizationId);
 				this.MessageToSubmit.Sender = new Participant(iadsystemConfigurationLookup.GetMicrosoftExchangeRecipient());
 			}
 		}

 		protected void WriteHeaderFile(string headerFileName)
 		{
 			using (FileStream fileStream = File.Open(headerFileName, FileMode.Create, FileAccess.Write, FileShare.None))
 			{
 				using (StreamWriter streamWriter = new StreamWriter(fileStream))
 				{
 					if (this.MessageType != null)
 					{
 						streamWriter.WriteLine("MessageType : " + this.MessageType);
 					}
 					streamWriter.WriteLine("ProcessedCount : " + this.processedCount.ToString(CultureInfo.InvariantCulture));
 					if (this.messageID != null)
 					{
 						streamWriter.WriteLine("MessageID : " + this.messageID);
 					}
 					if (this.sentTime.Year != 1)
 					{
 						streamWriter.WriteLine("SentTime : " + this.sentTime.ToString(CultureInfo.InvariantCulture));
 					}
 					this.WriteCommonHeaderFields(streamWriter);
 					this.WriteCustomHeaderFields(streamWriter);
 				}
 			}
 		}

 		protected virtual void WriteCommonHeaderFields(StreamWriter headerStream)
 		{
 			if (!this.CallerId.IsEmpty)
 			{
 				headerStream.WriteLine("CallerId : " + this.CallerId.ToDial);
 			}
 			if (this.helper.RecipientName != null)
 			{
 				headerStream.WriteLine("RecipientName : " + this.helper.RecipientName);
 			}
 			if (this.helper.RecipientObjectGuid != Guid.Empty)
 			{
 				headerStream.WriteLine("RecipientObjectGuid : " + this.helper.RecipientObjectGuid.ToString());
 			}
 			if (this.helper.CallerName != null)
 			{
 				headerStream.WriteLine("CallerNAme : " + this.helper.CallerName);
 			}
 			if (!string.IsNullOrEmpty(this.helper.CallerIdDisplayName))
 			{
 				headerStream.WriteLine("CallerIdDisplayName : " + this.helper.CallerIdDisplayName);
 			}
 			if (this.CallerAddress != null)
 			{
 				headerStream.WriteLine("CallerAddress : " + this.CallerAddress);
 			}
 			if (this.helper.CultureInfo != null)
 			{
 				headerStream.WriteLine("CultureInfo : " + this.helper.CultureInfo);
 			}
 			if (this.helper.CallId != null)
 			{
 				headerStream.WriteLine("CallId : " + this.helper.CallId);
 			}
 			IUMResolveCaller iumresolveCaller = this as IUMResolveCaller;
 			if (iumresolveCaller != null && iumresolveCaller.ContactInfo != null)
 			{
 				headerStream.WriteLine("ContactInfo : " + CommonUtil.Base64Serialize(iumresolveCaller.ContactInfo));
 			}
 			headerStream.WriteLine("TenantGuid : " + this.helper.TenantGuid.ToString());
 		}

 		protected UMRecipient CreateRecipientFromObjectGuid(Guid objectGuid, Guid tenantGuid)
 		{
 			return UMRecipient.Factory.FromADRecipient<UMRecipient>(this.CreateADRecipientFromObjectGuid(objectGuid, tenantGuid));
 		}

 		protected ADRecipient CreateADRecipientFromObjectGuid(Guid objectGuid, Guid tenantGuid)
 		{
 			if (objectGuid == Guid.Empty)
 			{
 				throw new HeaderFileArgumentInvalidException("ObjectGuid is empty");
 			}
 			ADRecipient adrecipient = ADRecipientLookupFactory.CreateFromTenantGuid(tenantGuid).LookupByObjectId(new ADObjectId(objectGuid));
 			if (adrecipient == null)
 			{
 				CallIdTracer.TraceDebug(ExTraceGlobals.VoiceMailTracer, 0, "Could not find recipient {0}", new object[]
 				{
 					objectGuid.ToString()
 				});
 				throw new InvalidObjectGuidException(objectGuid.ToString());
 			}
 			return adrecipient;
 		}

 		protected UMDialPlan InitializeCallerIdAndTryGetDialPlan(UMRecipient recipient)
 		{
 			UMDialPlan umdialPlan = null;
 			if (this.CallerId.UriType == UMUriType.E164 && recipient.ADRecipient.UMRecipientDialPlanId != null)
 			{
 				umdialPlan = ADSystemConfigurationLookupFactory.CreateFromADRecipient(recipient.ADRecipient).GetDialPlanFromId(recipient.ADRecipient.UMRecipientDialPlanId);
 				if (umdialPlan != null && umdialPlan.CountryOrRegionCode != null)
 				{
 					this.helper.CallerId = this.helper.CallerId.Clone(umdialPlan);
 				}
 			}
 			return umdialPlan;
 		}

 		protected string GetMailboxServerIdHelper()
 		{
 			IUMCAMessage iumcamessage = this as IUMCAMessage;
 			if (iumcamessage != null)
 			{
 				UMMailboxRecipient ummailboxRecipient = iumcamessage.CAMessageRecipient as UMMailboxRecipient;
 				if (ummailboxRecipient != null)
 				{
 					return ummailboxRecipient.ADUser.ServerLegacyDN;
 				}
 			}
 			return "af360a7e-e6d4-494a-ac69-6ae14896d16b";
 		}

 		protected string GetRecipientIdHelper()
 		{
 			IUMCAMessage iumcamessage = this as IUMCAMessage;
 			if (iumcamessage != null)
 			{
 				UMMailboxRecipient ummailboxRecipient = iumcamessage.CAMessageRecipient as UMMailboxRecipient;
 				if (ummailboxRecipient != null)
 				{
 					return ummailboxRecipient.ADUser.DistinguishedName;
 				}
 			}
 			return "455e5330-ce1f-48d1-b6b1-2e318d2ff2c4";
 		}

 		private MessageItem messageToSubmit;

 		private SubmissionHelper helper;

 		private string messageType;

 		private CultureInfo cultureInfo;

 		private string headerFileName;

 		private int processedCount;

 		private string messageID;

 		private ExDateTime sentTime;
+
+		private static Type[] contactInfoDeserializationAllowList = new Type[]
+		{
+			typeof(Version),
+			typeof(Guid),
+			typeof(PropTag),
+			typeof(ContactInfo),
+			typeof(ADContactInfo),
+			typeof(FoundByType),
+			typeof(ADUser),
+			typeof(ADPropertyBag),
+			typeof(ValidationError),
+			typeof(ADPropertyDefinition),
+			typeof(ADObjectId),
+			typeof(ExchangeObjectVersion),
+			typeof(ExchangeBuild),
+			typeof(MultiValuedProperty<string>),
+			typeof(LocalizedString),
+			typeof(ProxyAddressCollection),
+			typeof(SmtpAddress),
+			typeof(RecipientDisplayType),
+			typeof(RecipientTypeDetails),
+			typeof(ElcMailboxFlags),
+			typeof(UserAccountControlFlags),
+			typeof(ObjectState),
+			typeof(DirectoryBackendType),
+			typeof(MServPropertyDefinition),
+			typeof(MbxPropertyDefinition),
+			typeof(MbxPropertyDefinitionFlags),
+			typeof(OrganizationId),
+			typeof(PartitionId),
+			typeof(SmtpProxyAddress),
+			typeof(SmtpProxyAddressPrefix),
+			typeof(ByteQuantifiedSize),
+			typeof(Unlimited<ByteQuantifiedSize>),
+			typeof(List<ValidationError>),
+			typeof(ADMultiValuedProperty<TextMessagingStateBase>),
+			typeof(ADMultiValuedProperty<ADObjectId>),
+			typeof(StoreObjectId),
+			typeof(StoreObjectType),
+			typeof(EntryIdProvider),
+			typeof(SimpleContactInfoBase),
+			typeof(MultipleResolvedContactInfo),
+			typeof(CallerNameDisplayContactInfo),
+			typeof(PersonalContactInfo),
+			typeof(DefaultContactInfo),
+			typeof(UMDialPlan),
+			typeof(UMEnabledFlags),
+			Type.GetType("Microsoft.Exchange.Data.ByteQuantifiedSize+QuantifierProvider, Microsoft.Exchange.Data"),
+			Type.GetType("System.UnitySerializationHolder, mscorlib"),
+			Type.GetType("Microsoft.Exchange.Data.ByteQuantifiedSize+Quantifier,Microsoft.Exchange.Data"),
+			Type.GetType("Microsoft.Exchange.Data.PropertyBag+ValuePair, Microsoft.Exchange.Data"),
+			Type.GetType("System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"),
+			typeof(DialByNamePrimaryEnum),
+			typeof(DialByNameSecondaryEnum),
+			typeof(AudioCodecEnum),
+			typeof(UMUriType),
+			typeof(UMSubscriberType),
+			typeof(UMGlobalCallRoutingScheme),
+			typeof(UMVoIPSecurityType),
+			typeof(SystemFlagsEnum),
+			typeof(EumProxyAddress),
+			typeof(EumProxyAddressPrefix)
+		};
 	}
 }

The patch appears to add and use a typed allowlist for deserialization of a voicemail’s contact info, which is found in a header file alongside the voicemail itself. Other seemingly unprotected deserializations can be seen in the same class. (I think it’s just XML parsing.) My suspicion is that CVE-2021-26858 or CVE-2021-27065 could be used to write a malicious header file to C:\Program Files\Microsoft\Exchange Server\V15\UnifiedMessaging\voicemail, but it’s entirely possible a crafted voicemail could be sent instead. While I haven’t developed a PoC yet, I do have a good idea how to, assuming the patch analysis is correct. Better-resourced attackers should be able to exploit this issue in considerably less time.

The specifically patched code can be seen below:

[snip]
									else
									{
										if (!(text4 == "ContactInfo"))
										{
											goto IL_409;
										}
										Exception ex = null;
										try
										{
											try
											{
												using (MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(array[1])))
												{
													contactInfo = (ContactInfo)TypedBinaryFormatter.DeserializeObject(memoryStream, PipelineContext.contactInfoDeserializationAllowList, null, true);
												}
											}
											catch (ArgumentNullException ex)
											{
											}
											catch (SerializationException ex)
											{
											}
											catch (Exception ex)
											{
											}
											continue;
										}
										finally
										{
											if (ex != null)
											{
												CallIdTracer.TraceDebug(ExTraceGlobals.VoiceMailTracer, 0, "Failed to get contactInfo from header file {0} with Error={1}", new object[]
												{
													headerFile,
													ex
												});
											}
										}
									}
[snip]
[snip]
		private static Type[] contactInfoDeserializationAllowList = new Type[]
		{
			typeof(Version),
			typeof(Guid),
			typeof(PropTag),
			typeof(ContactInfo),
			typeof(ADContactInfo),
			typeof(FoundByType),
			typeof(ADUser),
			typeof(ADPropertyBag),
			typeof(ValidationError),
			typeof(ADPropertyDefinition),
			typeof(ADObjectId),
			typeof(ExchangeObjectVersion),
			typeof(ExchangeBuild),
			typeof(MultiValuedProperty<string>),
			typeof(LocalizedString),
			typeof(ProxyAddressCollection),
			typeof(SmtpAddress),
			typeof(RecipientDisplayType),
			typeof(RecipientTypeDetails),
			typeof(ElcMailboxFlags),
			typeof(UserAccountControlFlags),
			typeof(ObjectState),
			typeof(DirectoryBackendType),
			typeof(MServPropertyDefinition),
			typeof(MbxPropertyDefinition),
			typeof(MbxPropertyDefinitionFlags),
			typeof(OrganizationId),
			typeof(PartitionId),
			typeof(SmtpProxyAddress),
			typeof(SmtpProxyAddressPrefix),
			typeof(ByteQuantifiedSize),
			typeof(Unlimited<ByteQuantifiedSize>),
			typeof(List<ValidationError>),
			typeof(ADMultiValuedProperty<TextMessagingStateBase>),
			typeof(ADMultiValuedProperty<ADObjectId>),
			typeof(StoreObjectId),
			typeof(StoreObjectType),
			typeof(EntryIdProvider),
			typeof(SimpleContactInfoBase),
			typeof(MultipleResolvedContactInfo),
			typeof(CallerNameDisplayContactInfo),
			typeof(PersonalContactInfo),
			typeof(DefaultContactInfo),
			typeof(UMDialPlan),
			typeof(UMEnabledFlags),
			Type.GetType("Microsoft.Exchange.Data.ByteQuantifiedSize+QuantifierProvider, Microsoft.Exchange.Data"),
			Type.GetType("System.UnitySerializationHolder, mscorlib"),
			Type.GetType("Microsoft.Exchange.Data.ByteQuantifiedSize+Quantifier,Microsoft.Exchange.Data"),
			Type.GetType("Microsoft.Exchange.Data.PropertyBag+ValuePair, Microsoft.Exchange.Data"),
			Type.GetType("System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"),
			typeof(DialByNamePrimaryEnum),
			typeof(DialByNameSecondaryEnum),
			typeof(AudioCodecEnum),
			typeof(UMUriType),
			typeof(UMSubscriberType),
			typeof(UMGlobalCallRoutingScheme),
			typeof(UMVoIPSecurityType),
			typeof(SystemFlagsEnum),
			typeof(EumProxyAddress),
			typeof(EumProxyAddressPrefix)
		};
[snip]
CVSS V3 Severity and Metrics
Base Score:
7.8 High
Impact Score:
5.9
Exploitability Score:
1.8
Vector:
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Attack Vector (AV):
Local
Attack Complexity (AC):
Low
Privileges Required (PR):
None
User Interaction (UI):
Required
Scope (S):
Unchanged
Confidentiality (C):
High
Integrity (I):
High
Availability (A):
High

General Information

Vendors

  • Microsoft

Products

  • Microsoft Exchange Server 2016 Cumulative Update 19,
  • Microsoft Exchange Server 2019 Cumulative Update 8,
  • Microsoft Exchange Server 2013,
  • Microsoft Exchange Server 2016 Cumulative Update 14,
  • Microsoft Exchange Server 2019 Cumulative Update 4,
  • Microsoft Exchange Server 2016 Cumulative Update 15,
  • Microsoft Exchange Server 2019 Cumulative Update 5,
  • Microsoft Exchange Server 2019 Cumulative Update 6,
  • Microsoft Exchange Server 2016 Cumulative Update 16,
  • Microsoft Exchange Server 2019 Cumulative Update 7,
  • Microsoft Exchange Server 2016 Cumulative Update 18,
  • Microsoft Exchange Server

Exploited in the Wild

Reported by:
Reported: March 03, 2021 6:38pm UTC (1 month ago)

Additional Info

Technical Analysis