MicrosoftExchangeServer服务器端请求伪造漏洞(CVE-2026-45504)漏洞"

admin 2026-10-20 13:58:48 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

Microsoft Exchange Server 服务器端请求伪造漏洞(CVE-2026-45504)漏洞

天黑说嘿话

2026年6月26日 08:55
浙江

在小说阅读器读本章

去阅读

以下文章来源于404号浪漫
,作者404号浪漫

404号浪漫
.

/\\00后被老板威胁的一天,等我出息了把华莱士丢给老板吃\\/ 搞一些安全漏洞文章分享,谢谢同志们关注

0x01 核心速览

【事件】 【影响】
Microsoft Exchange Server存在一处服务器端请求伪造漏洞 (CVE-2026-45504),经过身份验证的低权限用户可通过构造 WOPI 请求,读取 Exchange 服务器上的任意本地文件。 所有部署了 Microsoft Exchange Server 2019 且启用了 OneDrivePro/WOPI 功能的环境均受影响。攻击者只需一个低权限的认证账户即可利用该漏洞,导致服务器敏感文件(如配置、日志)泄露。CVSS 评分 8.8。

0x02 正文解读

2.1-漏洞发现与概述

HawkTrace的安全研究Batuhan Er 公开了此漏洞。任何 Microsoft Exchange的低权限已验证用户都可以在未授权的情况下读取服务器上的任意文件。该漏洞被收录于ZeroVault 平台,编号 CVE-2026-45504

概念验证

CVE-2026-45504 Microsoft Exchange 文件读取

CVE-2026-45504.py

https://github.com/hawktrace/CVE-2026-45504/blob/main/CVE-2026-45504.py

2.2-漏洞技术根源

漏洞存在于处理 WOPI (Web Application Open Platform Interface) 令牌的代码路径中。关键函数GetWacUrl通过 GetTokenRequestWebResponse 向攻击者控制的 URL 发送 HTTP 请求,并将响应中 XML 内 <WebApplicationUrl> 或 ` 的值作为基础地址,直接拼接到后续请求中。随后 Exchange 会通过WebClient.OpenRead()发起对该地址的请求。由于缺乏对返回地址的 scheme 校验,攻击者可以将WebApplicationUrl设置为file://协议的本地路径,例如file:///C:/windows/win.ini`,导致 Exchange 读取并返回该文件内容。

2.3-请求触发与攻击链

  • 低权限用户通过 Exchange Web 服务 (EWS) 创建一个 ReferenceAttachment,并指定一个攻击者控制的 ProviderEndpointUrl。

  • 当受害者尝试预览附件时,Exchange 后端会调用 GetWacAttachmentInfo → CreateWacAttachmentTypeForReferenceAttachmentAsync 等一系列方法,最终到达 GetWacUrl,向攻击者的服务器发起请求(如 /\_api/SP.Utilities.WOPIHostUtility.GetWopiTargetPropertiesByUrl(...))。

  • 攻击者的服务器返回一个包含 file:///C:/path/to/file# 的 XML 响应。

  • Exchange 随后会将 OAuth 参数拼接到此地址后方,形成 file:///C:/path/to/file#?access\_token=...&sc=...。由于 URL 解析器将 # 后的部分视为片段标识符而忽略,最终 Exchange 仅请求file:///C:/path/to/file,并将文件内容返回给攻击者。

2.4-绕过技术细节
GetWacUrl 包装函数会构建形如 {BaseUrl}&access_token={...}&sc=... 的 URL。若 BaseUrl 为 file:///C:/windows/win.ini,拼接后的路径会被视为错误路径。攻击者在路径末尾附加 # 字符,使拼接参数成为 URI 片段,从而被解析器丢弃,最终访问到正确的文件系统路径。这是关键的一个绕过步骤。

就像 SQL 注入和其他许多漏洞一样,利用#字符进行一些巧妙的操作。如果攻击者返回file:///c:/windows/win.ini的是 `<filename>` WebApplicationUrl,Exchange 会将请求构造成 ` file:///c:/windows/win.ini?...&access_token=...<filename>`,这会破坏文件路径。但是,通过附加一个#字符,系统会将该字符之后的所有内容视为片段并忽略,从而得到 ` file:///c:/windows/win.ini#?...&access_token=...<filename>`,这正是想要的文件。为了触发此漏洞,Exchange 会向我们的服务器发送以下请求,/_api/SP.Utilities.WOPIHostUtility.GetWopiTargetPropertiesByUrl(fileUrl=@p,requestedAction=0)?@p='http://hawktrace.local:80/'而我们则以 ` file:///C:/windows/win.ini#<filename>` 作为响应WebApplicationUrl,从而使整个过程能够按预期继续进行。

2.5-代码流程跟踪
详细的调用堆栈如下,展示从TryTwice函数(直接使用传入的 URL 创建 HttpWebRequest)开始,经 GetTokenRequestWebResponse、GetWacUrl、CreateMeetingNotes.GetWacUrlInfo 直至 GetWacAttachmentInfo.ExecuteAsync 的完整攻击路径,证实了 SSRF 如何被触发并返回文件内容。

TryTwice

private static WebResponse TryTwice(ICallContext callContext, string url, ICredentials credentials, WebHeaderCollection headers)\t\t{WebResponse webResponse = null;Exception ex = null;for (int i = 0; i < 2; i++)\t\t\t{HttpWebRequest httpWebRequest = WebRequest.CreateHttp(url);\t\t\t\thttpWebRequest.Method = \"GET\";\t\t\t\thttpWebRequest.Credentials = credentials;\t\t\t\thttpWebRequest.UserAgent = OneDriveProUtilities.UserAgentString;\t\t\t\thttpWebRequest.ContentType = \"application/json;odata=verbose\";\t\t\t\thttpWebRequest.PreAuthenticate = true;\t\t\t\thttpWebRequest.Headers.Add(headers);try\t\t\t\t{\t\t\t\t\tOneDriveProUtilities.EndBudget(callContext);IAsyncResult asyncResult = httpWebRequest.BeginGetResponse(null, null);\t\t\t\t\tasyncResult.AsyncWaitHandle.WaitOne();\t\t\t\t\twebResponse = httpWebRequest.EndGetResponse(asyncResult);\t\t\t\t}catch (WebException ex2)\t\t\t\t{\t\t\t\t\tex = ex2;\t\t\t\t\twebResponse = ex2.Response;\t\t\t\t}finally\t\t\t\t{\t\t\t\t\tOneDriveProUtilities.StartBudget(callContext, null, \"GetWacUrl\");\t\t\t\t}HttpWebResponse httpWebResponse = webResponse as HttpWebResponse;if (ex == null && httpWebResponse != null && httpWebResponse.StatusCode < HttpStatusCode.BadRequest)\t\t\t\t{return httpWebResponse;\t\t\t\t}StringBuilder stringBuilder = new StringBuilder();\t\t\t\tOneDriveProUtilities.GetRequestAndResponseDetails(stringBuilder, ex, httpWebRequest, httpWebResponse, null, null);if (callContext != null && callContext.ProtocolLog != null)\t\t\t\t{\t\t\t\t\tcallContext.ProtocolLog.Set(GetWacAttachmentInfoMetadata.RequestDetails, stringBuilder.ToString());\t\t\t\t}else\t\t\t\t{\t\t\t\t\tOwaServerTraceLogger.AppendToLog(OwaFeature.OneDrivePro, \"OneDrivePro.SendRestRequest\", null, \"HttpFailure\", stringBuilder.ToString());\t\t\t\t}\t\t\t}if (ex != null)\t\t\t{throw ex;\t\t\t}return null;\t\t}

获取令牌请求Web响应

private static WebResponse GetTokenRequestWebResponse(ICallContext callContext, OwaIdentity identity, string getWacTokenUrlFormat, string endPointUrl, string documentUrl, string actionOrAppId, string callingMethod = \"GetWacToken\", string eventId = \"SP.GWT\")\t\t{if (documentUrl.EndsWith(\"?web=1\", StringComparison.OrdinalIgnoreCase))\t\t\t{\t\t\t\tdocumentUrl = documentUrl.Substring(0, documentUrl.Length - 6);\t\t\t}string text = string.Format(getWacTokenUrlFormat, endPointUrl, HttpUtility.UrlEncode(documentUrl.Replace(\"'\", \"''\")), actionOrAppId);\t\t\tICredentials oauthCredential = OauthUtils.GetOauthCredential(identity.GetOWAMiniRecipient());\t\t\tWebHeaderCollection oauthRequestHeaders = OneDriveProUtilities.GetOAuthRequestHeaders();\t\t\toauthRequestHeaders[HttpRequestHeader.AcceptLanguage] = Thread.CurrentThread.CurrentCulture.Name;\t\t\tWebResponse webResponse;\t\t\t...\t\t\tExTraceGlobals.AttachmentHandlingTracer.TraceWarning<string, string>(0L, \"OneDriveProUtilities.{0} Exception while trying to get wac token using durable url. : {1}\", callingMethod, ex.StackTrace);\t\t\tdocumentUrl = documentUrl.Substring(0, documentUrl.LastIndexOf(\"?\", StringComparison.InvariantCulture));\t\t\ttext = string.Format(getWacTokenUrlFormat, endPointUrl, HttpUtility.UrlEncode(documentUrl.Replace(\"'\", \"''\")), actionOrAppId);\t\t\t\tExTraceGlobals.AttachmentHandlingTracer.TraceWarning<string, string>(0L, \"OneDriveProUtilities.{0} Fallback to canonical url format: {1}\", callingMethod, text);\t\t\twebResponse = OneDriveProUtilities.TryTwice(callContext, text, oauthCredential, oauthRequestHeaders);\t\t\t}return webResponse;\t\t}

GetTokenRequestWebResponse将给定的URL 转换为 SharePoint REST API 请求。

获取WacUrl

internal static WacUrlInfo GetWacUrl(ICallContext callContext, OwaIdentity identity, string endPointUrl, string documentUrl, bool isEdit, bool isSPGetWacTokenEnabled)\t\t{string text = (isEdit ? \"2\" : \"4\");if (isSPGetWacTokenEnabled)\t\t\t{\t\t\t\ttext = (isEdit ? \"1\" : \"0\");\t\t\t}string text2 = (isSPGetWacTokenEnabled ? \"{0}/_api/SP.Utilities.WOPIHostUtility.GetWopiTargetPropertiesByUrl(fileUrl=@p, requestedAction={2})?@p='{1}'\" : \"{0}/_api/Microsoft.SharePoint.Yammer.WACAPI.GetWacToken(fileUrl=@p, wopiAction={2})?@p='{1}'\");\t\t\tWebResponse tokenRequestWebResponse = OneDriveProUtilities.GetTokenRequestWebResponse(callContext, identity, text2, endPointUrl, documentUrl, text, \"GetWacToken\", \"SP.GWT\");\t\t\tXmlDocument xmlDocument = new XmlDocument();\t\t\tOneDriveProUtilities.EndBudget(callContext);\t\t\tXmlReaderSettings xmlReaderSettings = new XmlReaderSettings();\t\t\txmlReaderSettings.XmlResolver = null;\t\t\tXmlReader xmlReader = XmlReader.Create(tokenRequestWebResponse.GetResponseStream(), xmlReaderSettings);\t\t\txmlDocument.Load(xmlReader);\t\t\tOneDriveProUtilities.StartBudget(callContext, null, \"GetWacUrl\");string text3 = \"http://schemas.microsoft.com/ado/2007/08/dataservices\";string text4 = null;string text5 = null;string text6 = null;foreach (object obj in xmlDocument.GetElementsByTagName(\"*\", text3))\t\t\t{\t\t\t\tXmlNode xmlNode = (XmlNode)obj;if (xmlNode is XmlElement)\t\t\t\t{if (text4 != null && text5 != null && text6 != null)\t\t\t\t\t{break;\t\t\t\t\t}if (!isSPGetWacTokenEnabled && string.CompareOrdinal(xmlNode.LocalName, \"AppUrl\") == 0)\t\t\t\t\t{\t\t\t\t\t\ttext4 = xmlNode.InnerText;\t\t\t\t\t}else if (isSPGetWacTokenEnabled && string.CompareOrdinal(xmlNode.LocalName, \"WebApplicationUrl\") == 0)\t\t\t\t\t{\t\t\t\t\t\ttext4 = xmlNode.InnerText;\t\t\t\t\t}else if (string.CompareOrdinal(xmlNode.LocalName, \"AccessToken\") == 0)\t\t\t\t\t{\t\t\t\t\t\ttext5 = xmlNode.InnerText;\t\t\t\t\t}else if (string.CompareOrdinal(xmlNode.LocalName, \"AccessTokenTtl\") == 0)\t\t\t\t\t{\t\t\t\t\t\ttext6 = xmlNode.InnerText;\t\t\t\t\t}\t\t\t\t}\t\t\t}if (text4 == null || text5 == null || text6 == null)\t\t\t{\t\t\t\tStringBuilder stringBuilder = new StringBuilder();\t\t\t\tOneDriveProUtilities.GetRequestAndResponseDetails(stringBuilder, null, null, tokenRequestWebResponse, null, null);\t\t\t\tstringBuilder.AppendFormat(\"baseUrl: {0}, accessToken: {1}, accessTokenTtl: {2}\
\", text4, text5, text6);if (callContext != null && callContext.ProtocolLog != null)\t\t\t\t{\t\t\t\t\tcallContext.ProtocolLog.Set(GetWacAttachmentInfoMetadata.RequestDetails, stringBuilder.ToString());\t\t\t\t}else\t\t\t\t{\t\t\t\t\tOwaServerTraceLogger.AppendToLog(OwaFeature.OneDrivePro, \"OneDrivePro.SendRestRequest\", null, \"HttpFailure\", stringBuilder.ToString());\t\t\t\t}throw new OwaException(\"SharePoint's GetWacToken response is not usable.\");\t\t\t}\t\t\ttext4 = OneDriveProUtilities.ReplaceLanguageParametersOnWacUrl(text4, Thread.CurrentThread.CurrentCulture.Name);return new WacUrlInfo\t\t\t{\t\t\t\tBaseUrl = text4,\t\t\t\tToken = text5,\t\t\t\tTokenTtl = text6\t\t\t};\t\t}

GetWacUrl 这个函数本身会向攻击者指定的 URL 发起请求,这确实构成 SSRF。但仅仅“能发请求”还不够——真正的漏洞在于,函数会从返回的响应中提取 WebApplicationUrl 字段,并把这个字段的值当作“可信地址”,随后再用它发起第二次请求。攻击者正是通过控制这个字段的值(填入 file:// 路径),让 Exchange 去读取本地文件,从而实现了“文件读取”。

GetWacUrl(包装器)

internal static string GetWacUrl(ICallContext callContext, OwaIdentity identity, string endPointUrl, string documentUrl, bool isEdit, FeaturesManager featuresManager)\t\t{bool flag = featuresManager != null && featuresManager.ServerSettings.SPGetWacToken.Enabled;\t\t\tWacUrlInfo wacUrl = OneDriveProUtilities.GetWacUrl(callContext, identity, endPointUrl, documentUrl, isEdit, flag);string text = (isEdit ? \"OwaEdit\" : \"OwaView\");return string.Format(\"{0}&access_token={1}&access_token_ttl={2}&sc={3}\", new object[] { wacUrl.BaseUrl, wacUrl.Token, wacUrl.TokenTtl, text });\t\t}

GetWacUrl wrapper包装函数决定最终 URL 的格式,并将其构建为http://attacker.com/...&access_token=...&sc=....


0x03 动作指引

3.1-缓解与修复

  • 根本修复:需要对WOPI 端点返回的 WebApplicationUrl 实施严格的 scheme 校验,禁止file:// 及其他非 HTTP(S) 协议,之后再将值传递给WebClient.OpenRead()。
  • 临时措施:监控并限制 EWS 接口创建 ReferenceAttachment 的行为,审查 ProviderEndpointUrl 是否指向外部或非白名单服务器。
  • 补丁状态:截至原文发布时,文章未提及微软是否已发布安全更新。建议持续关注微软安全公告,并尽快应用相关补丁。

3.2-检测建议

  • 检查 Exchange 服务器 OwaServerTraceLogger 或协议日志中是否出现对 file:// 协议地址的请求痕迹。
  • 监测:Microsoft.Exchange.Clients.Owa2.Server.Core.OneDriveProUtilities.TryTwice 方法调用时传入的 URL 参数。
  • 利用 IIS 日志或 Exchange 应用程序日志筛查包含 /\_api/SP.Utilities.WOPIHostUtility.GetWopiTargetPropertiesByUrl 且响应中 WebApplicationUrl 含有 file:// 的请求。

0x04 参考链接

  • HawkTrace 团队博客:https://hawktrace.com/blog/CVE-2026-45504/
  • ZeroVault 平台:https://zerovault.io

MicrosoftExchangeServer服务器端请求伪造漏洞(CVE-2026-45504)漏洞" 网络安全文章

MicrosoftExchangeServer服务器端请求伪造漏洞(CVE-2026-45504)漏洞"

MicrosoftExchangeServer存在服务器端请求伪造漏洞CVE-2026-45504,经身份验证的低权限用户可通过构造WOPI请求读取服务器任意本地文件。漏洞源于GetWacUrl函数未校验返回地址的协议类型,攻击者利用file://协议和#字符绕过参数拼接机制实现文件读取。影响所有启用OneDrivePro/WOPI功能的Exchange2019环境,CVSS评分8.8。建议及时更新补丁并禁用相关功能缓解风险。
【高危漏洞预警】CiscoCatalystSD-WANManager零日提权CVE-2026-20245" 网络安全文章

【高危漏洞预警】CiscoCatalystSD-WANManager零日提权CVE-2026-20245"

本文预警了CiscoCatalystSD-WANManager的高危零日提权漏洞CVE-2026-20245。该漏洞源于输入验证不足,允许拥有netadmin权限的攻击者通过上传恶意配置文件触发命令注入,从而提升至系统root权限。这可能导致攻击者完全控制管理平台,并向全网分支设备推送恶意配置,造成全域内网渗透风险。目前尚无官方补丁,建议立即采取措施:收紧netadmin账号权限(如强制MFA、强密码策略)、隔离管理平面网络边界、监控特定日志以检测可疑活动,并准备应急处置流程以应对潜在入侵。
应对量子计算“生存威胁”:美国国防部发布后量子密码战略" 网络安全文章

应对量子计算“生存威胁”:美国国防部发布后量子密码战略"

美国国防部发布后量子密码战略以应对量子计算带来的生存威胁,要求所有系统最迟于2030年支持、2031年使用后量子密码。该战略提出八大目标与五大工作方向,涵盖治理优化、系统盘点、技术开发、商业方案整合及抗量子设备部署,并强调迁移过程需保持作战能力、淘汰漏洞算法且不引入新风险。
Aiagent安全任重而道远" 网络安全文章

Aiagent安全任重而道远"

该文档为2026年6月26日发布的原创文章,标题为‘Aiagent安全任重道远’,作者whoami0002,隶属于SecurityPaper平台。内容聚焦AI智能体安全领域发展现状与挑战,但具体技术细节和核心论点因文档内容缺失无法获取。
评论:0   参与:  0