微软Azure登录日志漏洞GraphGhost:失败登录背后的密码验证泄露

本文详细分析了微软Azure Entra ID中的GraphGhost漏洞,攻击者可通过特定错误代码在登录失败日志中确认密码有效性,微软已于2025年4月修复该问题。

Full Disclosure, GraphGhost: Are You Afraid of Failed Logins?

作者:@nyxgeek
发布日期:2025年6月5日
分类:漏洞评估

背景

Entra ID(前身为Azure AD)是Azure的身份认证核心组件,负责管理用户、应用程序和权限。用户和应用程序连接Azure服务时会生成登录日志,这些日志是Azure管理员的唯一信息来源。

虽然云服务简化了IT管理,但也带来了依赖性问题:管理员完全依赖云服务商提供的日志。当云服务商的逻辑出现错误时,管理员可能无法获取日志或获得错误日志——不知道真相和被提供错误信息,哪个更糟?

此类日志逻辑问题并非首次出现。GraphNinja(一种完整的日志绕过漏洞)曾在Azure中存在多年(详见博客文章)。该漏洞的原理是:通过Graph认证时,若将认证指向其他租户而非目标租户或通用端点,认证尝试不会记录在任何租户的登录日志中。GraphNinja已被修复,失败认证现在会显示在目标租户的日志中。

今天我将分享GraphGhost漏洞,与GraphNinja类似,但攻击者可在日志显示失败的同时确认密码是否有效。

工作原理

向Graph提交登录尝试时,需提供多个字段(取决于认证方法),例如:

  • 用户名
  • 密码
  • 资源ID
  • 客户端ID

提交正确值会获得令牌;提交错误值会收到错误信息——微软冗长的错误信息再次给防御者带来困难,却帮助了攻击者。

微软验证登录的有效性遵循以下顺序:

  1. 目标租户是否存在?
  2. 目标域是否存在?
  3. 用户(UPN)是否存在?
  4. 密码是否有效?

这是日常遇到的主要步骤。登录要么成功,要么因用户名或密码错误而失败。

但密码验证之后的步骤呢?其他提交的字段(如客户端ID、UPN是否在正确租户、请求资源是否有效)会在密码验证通过后检查。下图展示了已映射的检查流程:

图3 - Graph认证操作顺序

问题

任何密码验证后的检查失败都会导致整个登录被视为失败。但由于我们了解操作顺序,可以知道哪些错误代码仅在密码验证成功后出现。

下图再次展示了流程,并标明了密码验证后的检查:

图4 - 此处有龙!

红线以下的任何错误代码都表示已找到有效密码。

发起请求很简单,以下是两个执行登录尝试的curl请求示例:

图5 - 使用Curl演示

日志中的失败记录如下:

图6 - GraphGhost登录日志
图7 - GraphGhost - 失败登录列表

或另一个示例:

图8 - GraphGhost - 失败登录详情

当认证通过后发生任何失败时,登录状态会显示为“失败”。即使查看认证详情标签,也没有任何指示:

图9 - GraphGhost - 认证详情

注意密码认证的“成功”列显示为false。管理员审查此日志时,无法发现凭据已泄露。

需要明确的是:这仅让攻击者知道密码有效,但未获得有效令牌。此类攻击的目的是,一旦获知账户密码,攻击者可更精准地使用该凭据——例如在目标区域通过VPN登录,或在正常工作时间登录;攻击者还可使用受害者企业凭据 targeting Wi-Fi,完全绕过MFA。无论如何,管理员对密码泄露一无所知绝非好事。

修复

我曾希望微软借此机会反思其冗长错误代码的使用——它们帮助了谁?管理员本就可以查看实际日志和生成的错误代码;唯一受益者是攻击者。

但遗憾的是,微软未采取此路线:

图10 - 经典的微软

截至2025年4月11日,此问题已修复。微软最终更新了认证详情,以指示密码已成功验证——虽是小改动,但至关重要:

图11 - GraphGhost - 旧版vs新版

时间线

  • 2024年12月17日 - 向微软报告
  • 2024年12月17日 - 微软开案
  • 2025年2月21日 - 确认并授予奖金
  • 2025年4月11日 - 微软修复

思考

如前所述,我曾希望微软借此推动整体安全提升。此问题并不难发现,我困惑于GraphGhost及早期的GraphNinja日志问题为何未被微软自身安全团队识别。与GraphNinja一样,微软未公开提及此漏洞。作为自身的CVE编号机构(CNA),微软可决定什么是漏洞,以及公众应知悉什么。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计