我本可访问 17 万亿条 Microsoft 记录
估计有 17.3 万亿条存储记录——横跨 Microsoft 多个数据集——都能通过一个内部分析服务访问,原因仅仅是它从不校验登录令牌的签名。这个漏洞让我可以冒充管理员身份,在没有任何真实凭证的情况下提交未经授权的 SQL 查询。我只用表描述、元数据和限量采样行来了解潜在的影响范围。
先说明两点。我描述的影响是假设性的,即攻击者拿到这种访问权限本可以做什么。幸运的是发现漏洞的是我,我报告了它,从未触碰任何客户数据或 PII。另外为了透明起见:Microsoft 对本文拥有编辑权,发布前删减了部分章节和图片,并调整了影响描述的方式。
Microsoft 对此发现的回应如下:
“我们感谢有机会调查 Faav 报告的发现。其提交和协调漏洞披露帮助我们通过加固服务更好地保护客户。我们重视并感谢符合 Microsoft 漏洞赏金计划条款的安全漏洞研究,期待未来继续与 Faav 合作。”
嗨!我是 Faav。一年多以前,15 岁的我发布了第一篇 Microsoft 漏洞分析文章 Break into any Microsoft building: Leaking PII in Microsoft Guest Check-In。现在我 16 岁了,这次的发现规模更大。
从那以后我全身心投入漏洞赏金。这一年里我在课余时间断断续续地挖 Microsoft 的洞,也在 Amazon、Google、Adobe 和其他不少公司发现了漏洞。我还开始把 AI 融入挖洞流程,由此开发了我的个人 AI 黑客助手 Antares。
这次的发现源于 Antares 没能完成的一条自动化线索。十天之后——经历了一个周五的课业,加上一次深夜的直觉——它变成了我挖到的最严重的 Microsoft 漏洞。
发现 Titan API
2026 年 8 月 25 日,Antares 发现了一个名为 Titan 的 Microsoft 内部服务。它的 Web 界面藏在一个面向 Microsoft 员工的 VPN REQUIRED 页面后面,前端无法直接访问。但上了锁的前门什么时候挡住过人?

非员工访问 Titan 前端时看到的“需要 VPN”页面。
该 API 在前端没有任何链接,因此 Antares 搜索了 Microsoft 的子域名,发现了一个指向 Azure Cloud Services 主机的独立端点。其公开的 Swagger 文件列出了四个路由:
/GetConfiguration
/GetOnboardedTables
/v2/Query
/v2/Insert
Swagger 文档指定其中三条路由使用 Azure AD bearer 认证,唯一例外是 /v2/Query,而它恰恰也支持原始 SQL 输入。不出所料,我便从这里开始探测。
查询需要一个 tableName 参数,但 Swagger 未提供示例值。我从 Wayback Machine 提取了 Titan 登录页和隐私页的 2023 年快照,阅读归档的 Superset 配置后恢复了 56 个表定义,其中包括一个名为 TestData 的路由值。

当前 VPN 限制生效前归档的 Titan 界面。
我用该值对在线 API 进行了尝试:
POST /v2/Query HTTP/1.1
Host: [已隐藏]
Content-Type: application/json
{"query":"SELECT 1","tableName":"TestData","rowLimit":1}
由于没有携带认证头,请求返回了 401 Unauthorized,Antares 便开始探查其如何验证 JWT。
突破 JWT 验证
在接下来的十几天里,在处理其他数百条线索的同时,Antares 反复聚焦 Titan,逐个解决其 JWT 检查中的报错。
起初使用我外部 Entra 测试租户的令牌,该令牌数月前提前创建并常用于测试,Titan 抛出租户错误。将租户改为 Microsoft 后出现受众错误,再改受众则触发应用白名单错误,替换应用 ID 后终于进入了用户查找阶段。
载荷不断变化,签名却始终一致,而 Titan 接受新声明,如同门卫检查证件上的名字却从不核对照片。这是它未验证签名的首个重要迹象。
在我使用 AI 之前,曾手动利用过未签名 JWT 绕过漏洞,因此我立即识别出这一模式。
随后,我使用如下头部信息,将一个完全合成的 JWT 替换了原令牌:
{"alg":"none","typ":"JWT"}
典型的签名 JWT 由三个非空部分构成:header.payload.signature。但我的 JWT 以裸句号结尾,因为第三段是空的:
base64url(header).base64url(payload).
Titan 根本没有校验签名。
Payload 使用了 Titan 预期的字段,但其中的 upn 是由我控制的:
{
"aud": "[redacted]",
"tid": "[redacted]",
"appid": "[redacted]",
"upn": "[email protected]",
"oid": "00000000-0000-0000-0000-000000000000"
}
这个无签名的 JWT 成功通过了租户、受众和应用校验,然后返回:
User '[email protected]' not found
Antares 在跟进这条线索,运行了 Codex 和 Claude。因为 UPN 通常是 Entra 身份体系中采用邮箱格式的用户名,两个模型都在测试占位符、公开的服务别名以及类似 Microsoft 员工格式的邮箱。
无签名 JWT 已经能触达 Titan 的本地用户查找逻辑,但 Antares 始终找不到 Titan 认可的 UPN,因此无法生成有效查询,也没有可演示的影响面,这条线索就停留在“有疑点”的阶段。
尝试 admin
整个周五我都忙着做功课。等到 Titan 的线索再次浮现、我决定亲自再深挖时,已是 9 月 5 日周六凌晨 1 点以后。
我试了几个看起来合法的 UPN,同样失败。于是我不再瞎猜,而是开始分析后端实际如何消费这个 claim。如果后端是用 upn 查找本地应用用户名呢?我把无签名 JWT 中的 upn 从邮箱格式改成 admin。
结果只有一个数字 1。但在经历了整整十天的认证失败后,这个 1 极具意义。我实际上已经以 Titan 的管理员身份执行 SQL 了。

Titan 接受了无签名的管理员身份并执行了 SQL 查询。
有趣的是,admin 这个值太明显了,明显不是合法 UPN——这正是 Antares 始终没猜到的原因。我之所以试出来,是因为我没再死抠字段名,而是去想开发者在底层可能做了什么。
Titan 把未签名的 upn claim 直接当作本地用户名来用。admin 解析到了本地用户 ID 1,该用户拥有 Admin 角色,于是 SQL 就执行了。有时候,答案真的就是 admin。
深入数据库
我先试了 TestData,本以为里面只有假数据,结果也确实如此:测试库里放着测试用例。但 SHOW DATABASES 列出了其余的数据库,其中包括 Titan 的平台元数据库。从这里开始,我可以直接查询应用层的表了。
元数据库里存着真实数据。我第一个看到的是一张活跃应用用户账号表,包含姓名、邮箱地址和登录历史。整个平台元数据包括:
- 约 25,000 条账号和邮箱记录。
- 17,990 条员工邮箱记录。
- 15,001 条员工组织架构记录。
- 355 个数据库配置。
- 20,979 个虚拟数据集 SQL 定义。
- 24,569 个仪表盘、425,891 个图表和 27,347 个数据集定义。

一条应用用户记录,含身份信息和登录活动。密码字段存放的是 Superset 本地用户模型生成的占位哈希,并非真实的微软凭证。敏感信息已做脱敏处理。
Titan 的用户和用量目录暴露了相关员工的详细信息,比如职位、部门和汇报关系。这些数据只覆盖了部分微软员工,并非完整的员工名录。虽然我没实际测试或演示,但这些信息本可以被攻击者用来实施有针对性的社会工程攻击。
到这一步,员工数据看起来是主要发现。随后我注意到一个独立的 Bing 分析数据源。
验证有边界的 Bing 分析样本
我从最新可用的 Bing 分析分区中请求了一行数据。第二条单行查询又从同一分区返回了另一条不同的记录。这些有限的样本足以证明 Bing 搜索分析数据可以通过该服务访问。我把测试严格控制在两次单行查询。而 Bing 只是能这样访问到的数据库之一。

一条包含搜索、标识符和高层级位置字段的分析记录。我的查询仅提取了可用字段中的一小部分。请注意,位置值并不包含精确的用户定位,而是通过反向 IP 解析得到的国家或州级信息。敏感数值已做脱敏处理。
由于 MUID 出现在多个数据集中,用户行为理论上可以在不同服务间进行关联,尽管我从未实际执行过此类操作。我没有识别出任何具体个人,没有在数据集间链接记录,也没有基于抽样数据构建任何用户画像。
发现员工记录后,我便开始起草提交给 MSRC 的报告。看到 Bing 数据后,我立刻进行了上报。
17.3 万亿行数据
数据的总规模是我最后才弄清楚的。
我用 SELECT 1 测试了归档配置中全部 56 个路由值。其中 30 个仍然处于活跃状态。每个路由值指向一个后端配置,而每个配置包含一个或多个数据库,因此这 30 个活跃值经过 24 个配置的解析,最终连接到横跨 9,863 个唯一表名的 17 个分析数据库。
没有一个现成的总计数。我从 17 个 ClickHouse 数据库获取了各自的元数据统计,于是把这些数据交给 AI 求和,同时自己检查每个 Distributed 表如何映射到其底层集群。我按每个分片一个副本进行计数,并通过两条元数据路径验证总数:system.tables.total_rows 和活跃的 system.parts。
求和结果返回的原始数字没有格式化:
17333335124315
我得把它分成三位一组才能看懂:
17,333,335,124,315
十七万亿——这是基于元数据的存储估算值,很可能包含历史数据、重复数据和衍生数据,但数字依然极其庞大。这就是通过该漏洞在技术上可触达的环境规模估算。
我第一反应是副本被重复计算了,或者不小心多了几个零。我再次检查。事实并非如此。两条路径返回的都是同一个数字。
当时是凌晨两点。我想喊一声,哪怕只是说点什么出声,但父母已经睡了。于是我只是坐在那里,盯着 17,333,335,124,315,又把计算验了一遍。
结语
从这件事中,我有两点体会。
首先,AI 与人类直觉在此协同发挥。Antares 完成了我无需亲自操劳的十天之功:枚举子域名、逐字段解析 JWT 报错信息、映射全量攻击面,并让无签名 Token 穿越四层校验。但它做不到的,是意识到 upn 并非真正的 UPN。事后看来,User not found 报错本应是关键信号。此时构建的 JWT 已通过 Titan 的鉴权检查,系统仅是尝试将 upn 匹配其内部用户列表。单靠 Antares 或单靠我都无法抵达此步,正是它的坚持加上一闪念的直觉,才让这次发现成为可能。
其次,谈漏洞本身。Titan 校验了 JWT 内容(租户、受众、App ID、用户),却从未验证签名,而这是任何鉴权逻辑中核心的一环。这套鉴权检查好比酒店里所有门都配有正常工作的刷卡器,但任何一张卡都能刷开任意房间。尽管应用内存在完整的访问控制逻辑,唯独缺失的这一环使其全盘失效。若你是开发者(或编码智能体),阅读本文最需铭记的一点是:构建鉴权机制时,务必优先验证签名。
时间线
- 08/25/26 - Antares 发现 Titan 公开 API 并归档为线索。我从 Wayback Machine 恢复了存档的 Superset 配置及其 56 张表定义。
- 08/25/26–09/05/26 - Antares 反复攻坚 Titan 的 JWT 校验,并测试了电子邮件格式的 UPN。
- 09/05/26 - 我重新审视该请求,将
upn改为admin,SQL 查询随即生效。 - 09/05/26 - 确认可访问 30 个在线路由目标及 17 个连接的 Analytics 数据库(未拉取底层数据),随即向 MSRC 上报漏洞。同日开启 Case 144051。
- 09/06/26–09/08/26 - MSRC 要求我停止测试,并索取 IP 地址以核实是否存在超出安全研究范畴的活动。对方确认该问题已获优先处理。
- 09/09/26 - 该 API 端点被加固封锁。MSRC 表示该上报直接触发即时排查与修复,以消除剩余暴露面。
- 09/17/26 - 获 5,000 美元赏金
- 09/22/26 - 与 Microsoft 会面,讨论该发现并协调披露事宜。