乐于分享
好东西不私藏

从平方根到 /root:用 Excel 中的 Python 在 Azure 容器里提权

从平方根到 /root:用 Excel 中的 Python 在 Azure 容器里提权

威胁简报

恶意软件

漏洞攻击

概括

SafeBreach Labs研究员 Ron Ben Yizhak 对微软 Excel 中 Python 功能背后的隔离 Azure 容器环境进行了逆向工程,发现了一个符号链接漏洞,该漏洞允许他将权限从非特权用户提升至 root 用户。凭借这一权限,他恢复了一个内部配置文件,从而暴露了该功能背后的架构和主机名。之后,他发现微软的容器镜像可以匿名拉取,并且该环境中甚至集成了一个未公开的 AI 代理框架。此外,他还找到了一种绕过 Excel 可信记录安全控制(CVE-2026-45459)的方法:通过滥用 Python 结果对象,强制受害者的计算机静默获取一个 URL,并将数据自动上传到本应与网络隔离的容器中。这两个问题都已负责任地披露给微软,并在 2026 年 3 月至 6 月期间进行了修复。这项研究最初在 DEF CON 34 上发表,强调云隔离声明和 AI 集成生产力功能需要像任何其他信任边界一样接受同样的安全审查。


在 Excel 中使用 Python 是微软针对现代数据分析提出的解决方案,它直接应用于几乎所有企业用于财务、运营和报告的电子表格中。为了确保安全,微软不会在用户的笔记本电脑上运行 Python 代码。相反,它会将代码部署到 Azure 中一个专用的、与虚拟机隔离的容器中运行,并将结果仅返回给用户。微软官方文档将此环境描述为安全、非持久化,并且限制了本地和网络访问。从理论上讲,这听起来就像一个完全封闭的黑匣子。

在接下来的博客中,我将概述我最新的研究项目——该项目于今年8月在DEF CON 34大会上首次发表——阐述了我如何像玩密室逃脱游戏一样攻克这个环境:从容器内一个普通的非特权shell开始,绘制出我能找到的每一个进程、服务和未公开的API,并利用这张地图找到通往root权限的路径。我将解释这条路径如何最终让我获得对微软容器镜像的完全读取权限,以及一个内部配置文件,该文件详细阐述了整个解决方案的架构,其中还包含一些线索,表明一个AI代理框架正在运行于相同的容器内。最后,我将介绍另一项发现:一种利用Excel中的Python漏洞绕过Excel自身安全控制,并强制受害者的机器连接到攻击者控制的服务器的方法。最后,我将介绍微软的回应以及安全团队可以采取哪些措施来评估和降低与这些漏洞相关的风险的建议。 

概述

主要发现

我完全以一个权限较低、安全性不高的用户身份,在微软的 Python in Excel 容器内进行操作,并成功做到了以下几点:

  • 通过滥用文件上传机制中的符号链接,将非特权 Jupyter 用户权限提升到 Azure 托管执行容器内的 root 用户权限,该机制用于在 Excel 和容器之间移动数据。

  • 无需任何身份验证即可匿名拉取 Microsoft 的容器镜像,从而完全离线访问 Excel 中 Python 运行所需的文件系统、配置和二进制文件。

  • 从容器中恢复敏感的内部配置文件,该文件记录了服务主体、租户 ID、数据库和密钥库位置以及与政府和安全云部署相关的主机名,实际上是后端架构的映射。

  • 列举了全球数百个容器主机,并确认 root 权限提升对我测试的每一个主机都有效,包括运行未发布的“pilot”和“canary”版本的主机。

  • 发现一个未公开的 AI 代理框架与 Python 执行环境并行运行,引用子代理和技能来生成 Office 文档、搜索企业数据源和获取任意网络内容,这引发了人们的疑问:此功能是否有可能被滥用以窃取企业文档或代表受害者发送恶意内容。

  • 利用 Excel 中 Python 结果格式的一个特性,绕过 Excel 的受信任记录保护(CVE-2026-45459),该机制旨在要求用户在代码运行前批准代码执行,强制客户端计算机静默地从任意 URL 获取数据,然后将该数据上传到原本与网络隔离的容器中。

要点总结

这项研究的意义在于,它为任何运行 Microsoft 365 的组织以及任何构建类似云隔离执行功能的供应商提供了一些重要的经验教训:

  • 始终遵循最小权限原则。微软在此功能中内置了真正的安全控制措施:虚拟机管理程序隔离、非持久容器、限制本地和网络访问。此外,他们确保以低权限执行客户端代码,并禁止访问他们想要隐藏的信息,但并非客户端执行的每个操作都是以低权限进行的。我可以使用 root 权限上传文件,并利用这一点提升了我的权限。

  • 低权限进程所能获取的信息本身就是一种风险。早在我发现权限提升漏洞之前,对容器内部进行简单的侦察——读取环境变量、列出进程、检查已安装的库——就能获取内部主机名、服务名以及一些未公开功能的线索。所有这些都不需要提升的访问权限。构建隔离执行环境的组织应该假设,沙盒用户能够看到的一切,攻击者最终也能看到。

  • 人工智能驱动的新功能扩大了传统风险的影响范围。例如,一款具备文档生成、企业搜索和网页抓取功能的AI代理框架,竟然能在与Excel中运行Python相同的底层架构下运行,这提醒我们,随着供应商竞相将AI代理嵌入到生产力工具中,这些代理的安全模型也需要像托管它们的平台一样受到严格审查,尤其是在涉及企业数据访问的情况下。

  • 旧的攻击模式在新功能中仍然有效。微软在 Excel 中实现 Python 时,原本希望避免 Visual Basic 和 Excel 4.0 宏造成的安全问题(这些问题允许攻击者向工作簿中植入恶意软件),但返回给 Excel 的一个独特的 Python 对象却强制客户端执行与 Excel 4.0 宏相同的操作。

背景:Excel 中的 Python 是什么

Excel 中的 Python 功能允许用户直接在工作表中编写 Python 代码,引用单元格值并返回图表、数据框或计算值等结果,所有这些都可访问 NumPy、pandas 和 Matplotlib 等常用库。由于在 Office 文档中嵌入完整的脚本语言有着悠久而令人担忧的历史(例如,Visual Basic for Applications 几十年来一直是恶意软件传播的常用工具),微软在设计此功能时确保 Python 代码本身永远不会接触到最终用户的计算机。 

相反,代码会被发送到微软云端,在客户组织合规边界内的专用 Azure 容器中执行,并将结果返回到工作簿。工作簿关闭时,容器及其数据会被销毁。该容器也被描述为没有直接的网络访问权限,也无法访问客户端的本地计算机或帐户。从理论上讲,这是一个合理的安全模型。我的研究旨在对其进行实践验证。

探索环境

任何安全研究人员在获得初始访问权限后运行的第一个命令都是 `whoami`。在本例中,得到的结果是 jovyan,这是 Jupyter Notebook 部署使用的默认用户名。

这说明Python代码并没有直接执行。相反,它运行在一个持久化的Jupyter内核中,采用逐个单元格的执行模型,并且状态会在计算之间传递。jovyan用户被刻意设置为非特权用户,但非特权用户并不等同于对代码一无所知。

这说明Python代码并没有直接执行。相反,它运行在一个持久化的Jupyter内核中,采用逐个单元格的执行模型,并且状态会在计算之间传递。jovyan用户被刻意设置为非特权用户,但非特权用户并不等同于对代码一无所知。

列出正在运行的进程证实了环境的结构:一个以 root 用户身份运行的入口脚本,一个以非特权 jovyan 用户身份运行的 Jupyter notebook,以及两个额外的服务:一个代码执行服务和一个 HTTP 代理,两者都以 root 用户身份运行。

文件系统权限显示,存放 root 用户拥有的服务二进制文件的目录已被锁定,jovyan 无法读取,但一个单独的应用程序目录(/app)则可以正常访问。/app 是容器镜像创建的一个特殊目录,并非 Linux 发行版的默认目录。Python 及其所有模块和库都安装在该目录中。

到目前为止,我已经发现了一些 Web 服务。具体来说,有一个代理服务器和一个名为代码执行服务的程序,它们都与我们运行在同一个容器中。此外,还有一个服务运行在网络中的另一台机器上。这台机器的主机名无法在线解析。这是一台专用服务器,只能从容器内部访问。环境变量告诉我一些关于它的信息:它的端口、几个端点以及它的名称:出站代理。探测我识别出的这三个 Web 服务,让我对整个情况有了更清晰的了解。 

代理服务器拒绝了所有出站请求,返回 HTTP 403 错误;完全移除代理服务器后,连接超时,证实了微软的说法,即该容器没有真正的网络访问权限。

本地代码执行服务对直接查询仅返回一个神秘字符串“代码执行服务 ||”,除此之外没有提供任何其他信息。我找不到任何它暴露的端点。

只能从容器内部访问的出站代理拒绝了请求,并返回 401 身份验证错误:“您需要进行身份验证才能访问此资源。” 又一道锁着的门,却找不到钥匙。

总结一下,在 Excel 中执行 Python 代码时,代码会发送到某个微软服务器,然后进入一个隔离环境。它在 Jupyter Notebook 容器中执行,该容器还运行着两个基于 .NET 的服务。据我所知,我的容器唯一可以访问的机器是出站代理服务器。

自动化沟通

通过 Excel 客户端与此环境交互既缓慢又受限。Excel 会截断过长的输出,而且每次代码执行都必须通过编辑单元格来触发。因此,我抓取了 Excel 生成的 HTTPS 流量,并手动重建了底层 API:首先向一个全局服务发送请求,该服务返回一个区域容器主机的地址;然后向该主机发送请求以启动一个新的运行时环境(返回运行时 ID 和环境 ID);最后,调用 batchexecute 函数,使用与研究人员 Microsoft 帐户关联的 bearer token 提交 Python 代码以进行执行。 

直接与 API 对话,而不是通过 Excel 用户界面,消除了 Excel 施加的人为限制,让我能够更快地完成工作,包括成功提取 Microsoft 自定义 Python 库的内容,而之前通过工作簿本身尝试这样做时总是超时。

已安装的库中有两个尤为突出: 

  • officepyai:一个用于读取 Excel 文件的小型库

  • excel:一个更大的库,用于处理代码执行结果的序列化,并且至关重要的是,它包含了用于向我以前无法访问的出站代理进行身份验证的客户端逻辑。 

Excel 库显示,代理的身份验证方案是简单的 HTTP 基本身份验证,由容器中已存在的两个环境变量构建而成:计算资源 ID 和密钥。它们分别用作基本 HTTP 身份验证的用户名和密码。这两个变量的值用冒号分隔成一个字符串,然后使用 Base64 编码。最终值会作为请求头发送。

我访问了之前相同的端点:/data(我通过环境变量知道这个端点),并且我的身份验证成功了!Python 类也指出此端点需要一个名为 url 的参数,但它的值仍然未知。 

我以为出站代理有一个预定义的网站列表,允许从中获取数据,但我尝试的任何 URL 都被拒绝,并显示错误消息“数据下载主机不受信任”。

寻找通往根源的路径

真正的突破来自 Excel 的文件上传机制,该功能允许 Python 单元格引用包含图像或其他二进制数据的单元格。对于小文件,数据会以 base64 编码的形式与 Python 代码一起通过单个请求上传。 

然而,较大的文件会被上传到容器文件夹/mnt/data_upload。这让我意识到之前我并不知道:文件上传机制有一个专用的 API。 

首先,我通过连接/data/start端点来启动上传。上传请求包含两个参数:数据 ID 和 etag,它们的值由客户端决定,而不是服务器。 

接下来,我联系了端点 /data/upload,并使用数据 ID 标识了我的调用——此请求的主体包含上传文件的二进制数据。 

在容器的文件系统中,每次上传都会创建三个文件:状态文件、etag 文件和数据文件。

stat 文件包含预定义的值,用于指示上传请求的状态。文件上传过程中,该文件会写入字符串“in progress”,上传完成后,则会写入字符串“ready”。etag 文件包含我之前调用 /data/start 端点时指定的值。data 文件包含我们上传文件的二进制数据。

这些文件位于一个直接由客户端控制的值派生的路径中:一个是环境创建时已知的运行时 ID,另一个是我自由选择的数据 ID。关键在于,这三个文件都是由 root 用户创建和拥有的,因为写入操作是由特权代码执行服务处理的,而不是由非特权 Jupyter 进程处理的。 

任何时候,当一个非特权进程能够预测一个 root 进程即将写入的路径,并且也能写入该路径时,就存在一个经典的符号链接攻击的绝佳机会:在写入发生之前,在可预测的路径上放置一个符号链接,root 进程最终会写入符号链接指向的任何位置。

不幸的是,每次写入数据文件之前,数据文件都会被重新生成,这导致所有已放置的符号链接都被重置。但是,代码执行服务每次写入 etag 文件时都会跟随该符号链接,并且其内容直接来自客户端完全控制的 URL 参数。 

这使得一个非特权进程能够让 root 用户拥有的服务将攻击者选择的内容写入攻击者选择的文件系统上的任何路径,但有两个真正的限制:有效载荷必须适合 URL 参数,并且由于服务器端的解码怪癖,它必须保持在可打印 ASCII 范围内(即从零到十六进制值 7f)。

虽然这些限制让事情变得复杂,但我认为 Linux 中的“设置用户 ID”(SUID)权限或许能有所帮助。拥有此权限的可执行文件会以其所有者的权限运行,而不是以执行它们的用户的权限运行。例如,如果 Jovyan 执行一个由 root 用户拥有且具有 SUID 权限的文件,那么它将以 root 用户的权限执行。幸运的是,容器中有很多这样的文件,例如 change age。我可以覆盖它,这样我的有效载荷就会以 root 用户身份执行。

由于有效载荷必须保持在 ASCII 范围内,我尝试用 bash 脚本覆盖 change age 文件。但是执行 bash 脚本时 SUID 权限不起作用——Linux 出于安全考虑,特意禁用了 shell 脚本的这种机制。覆盖该文件后,我的脚本是以 Jovyan 权限而非 root 权限执行的。 

在多次尝试编译符合限制条件的最小 ASCII 安全 ELF 文件后,有效载荷仍然无法以 root 权限执行。

最终的答案来自于观察 root 用户自身的行为。我编写了一个小型进程监控脚本,并在容器中运行。结果显示,代码执行服务会定期执行标准的 Linux stat 二进制文件,作为其正常运行的一部分。通过符号链接覆盖该二进制文件,然后只需等待,即可以 root 用户身份执行任意代码,而无需事先以非特权用户身份执行有效载荷。

总结一下:文件上传机制使用客户端已知且可访问的路径。客户端可以设置一个从可访问路径指向文件的符号链接,该链接将由 root 用户执行。

然后客户端将上传一个文件,并将有效负载隐藏在请求的 etag 参数中。

代码执行服务会将参数值写入 etag 文件,但实际上它会被写入 root 用户拥有的可执行文件。

几秒钟后,该服务将使用此文件执行其任务之一,执行我们的有效载荷,并将结果提供给我们。

有了这种根权限,我就可以进入任何我想进入的门。 

Root权限揭示了什么

我首先访问了一开始就被禁止访问的 /mnt/secrets目录。令人失望的是,它里面只有 HTTPS 证书,没有 API 密钥、令牌或私钥。不过,它也让我能够访问内部服务的完整二进制文件,然后我对其进行反编译,以探索其端点和内部逻辑。 

分析结果显示,内部变量和函数名称存在异常,包括对许可证绕过逻辑、仅用于测试的计算资源以及政府租户部署检查的引用。在服务二进制文件的目录中,还有一个名为deploymentdata.json的配置文件,其中包含 Excel 中 Python 解决方案的架构信息,包括: 

  • 服务主体身份、租户 ID,甚至电子邮件地址

  • 数据库信息,包括 Azure 容器注册表、数据库名称和 Cosmos DB 的 URL

  • 密钥保管库,包括服务主体使用的密钥的完整路径 URL 以及属于测试用户的密钥保管库名称

  • 有证据表明存在政府特定租户,包括几个带有关键词的主机名,例如 dod、usgovcloud、ic(意为情报界)和 scloud(很可能意为安全云或秘密云)。

这样的文件可以省去攻击者耗时的侦察工作,让他们直接获取解决方案架构及其各部分之间的关联方式。虽然没有泄露任何密码或凭证,但它确实能让通过配置错误的服务器或其他途径获得初始访问权限的攻击者更容易地进行横向移动。

这极大地推进了我的研究,因为它还为我提供了全球数百个容器主机地址。我发现的同一个root权限提升漏洞在我测试过的每个主机上都有效。

  • 观看演示:https://www.youtube.com/watch?v=-fDUhTIXVdE

在对 Excel 中的 Python 环境进行数月监控后,我注意到新增了一个名为 OFFICEPY_FULL_IMAGE_NAME 的环境变量。该变量暴露了容器镜像的确切名称,并且无需任何身份验证即可拉取镜像,从而实现了对所有版本镜像的完整离线文件系统访问,而无需任何安全漏洞利用。

在每个容器主机上查询此环境变量后,我发现存在多个镜像,而不仅仅是一个。而且所有镜像都无需身份验证即可公开访问,包括生产环境、金丝雀环境和试点环境。 

在一些较新的试点主机上,还运行着一个之前未记录的 Node.js 应用程序。 

当我打开 js 源代码时,发现其中包含了对 Anthropologie 和 OpenAI API 密钥的引用。 

该应用是一个 LLM API 代理处理程序,它会创建一个本地 HTTP 服务器来模拟 LLM API,但会将请求通过 WebSocket 路由到具有互联网访问权限的外部客户端。简单来说:当你向它发送请求时,由于容器是隔离的,它会将请求转发到另一个服务器。

这款应用不仅支持简单的提示,还配备了一系列子代理,用于生成办公文档、管理电子邮件等等。它还拥有许多技能,以下列出部分技能。 

例如,连接器搜索可以从 Jira 和 Salesforce 等外部来源检索信息;企业搜索查询企业内部来源;而网页抓取则收集网页的全部内容。根据微软的政策,这些活动都是不应该被允许的。

测试期间无法与该外部服务器建立活动连接,因此无法对其进行全面测试。但它的存在给企业安全团队提出了一个重要且悬而未决的问题:如果包含恶意 Python 代码的工作簿在受害者的 Microsoft 帐户下于此环境中执行,该代码最终是否可能通过集成的搜索或提取功能访问企业数据,或者使用代理代表受害者生成和发送内容?由于目前尚无关于此功能的公开文档,因此这些风险尚无法排除。

绕过 Excel 的可信记录控制 (CVE-2026-45459)

研究的最后阶段又回到了Excel客户端本身。微软明确表示,Python代码无法访问运行Excel的计算机,因此问题就变成了:包含Python代码的工作簿是否仍然可能被利用来直接攻击最终用户。

Excel 长期以来一直存在这个问题。Excel 4.0 的宏(一种早于 Visual Basic for Applications 的脚本机制)在本地执行,多年来一直被滥用以传播恶意软件。为此,微软添加了两项相互重叠的保护措施: 

Mark of the Web 会标记从互联网下载的文件,并将其保持只读状态,直到用户点击“启用编辑”。

可信记录(Trusted Records)需要在首次打开特定文件时额外点击一次才能启用代码执行,这通常迫使攻击者向受害者发出两次警告,而不是一次。

事实证明,第二层保护机制从未应用于包含 Python 代码的工作簿,而仅应用于最初为其设计的旧式宏类型和 Visual Basic。这意味着,包含嵌入式 Python 代码的工作簿只需单击一次即可执行,而不是两次。 

结合我之前在微软自己的 Python 库中发现的富值类(该类允许 Python 单元格返回表示 Web 图像的“富值”对象),第二个警告从一开始就变得无关紧要了:返回指向任意 URL 的 Web 图像对象会导致受害者的 Excel 客户端在工作簿打开的瞬间静默地获取该 URL,完全不需要任何额外的点击操作。 

观看演示:https://www.youtube.com/watch?v=_9KfY-nvkZk

更进一步,我可以使用第二个 Python 单元,将获取的数据上传回隔离的容器中,有效地利用受害者自己的机器将数据偷运过网络边界,而容器本身永远不允许跨越该边界。

观看演示:https://www.youtube.com/watch?v=y6arSS0dKxI

供应商回复

SafeBreach 致力于负责任地披露漏洞。2026 年 2 月 5 日,SafeBreach 已将权限提升至 root、未经身份验证的容器镜像访问、内部配置文件泄露以及 AI 代理框架提出的问题报告给了微软。微软通过在相关文件操作中添加符号链接检查解决了权限提升问题,该问题已在 2026 年 3 月 1 日发布的 16.0.19828.43251 版本中得到解决。

2026 年 3 月 23 日,微软单独报告了 Excel 端的一个漏洞,即 Trusted Records 绕过漏洞以及富值 Web 图像行为漏洞。微软分配了 CVE-2026-45459 号漏洞编号,并于 2026 年 6 月 9 日发布了针对 Excel 的补丁,以阻止其基于 Python 代码返回的 Web 图像对象发起网络连接。

对安全团队的建议

已启用 Excel 中 Python 功能的 Microsoft 365 组织应确认其 Excel 版本已针对 CVE-2026-45459 漏洞进行了修补,该版本必须包含 2026 年 6 月 9 日或之后的更新。除了修补漏洞之外,这项研究还支持一些值得安全团队重视的更广泛的实践:

  • 将执行代码的 Office 文档功能(无论是宏、Visual Basic 还是 Excel 中的 Python 等新增功能)视为持续的网络钓鱼和初始访问途径,并继续培训用户对未经请求的工作簿保持警惕,无论涉及哪种脚本机制。

  • 监控并限制 Office 应用程序触发的意外出站网络活动,因为此处的底层技术依赖于获取受信任的、已签名的应用程序代表攻击者发出网络请求。

  • 在广泛启用云托管代码执行功能之前,请直接向供应商询问有关云托管代码执行功能的隔离边界的问题,尤其是在这些功能与可能访问企业搜索或文档生成的 AI 代理功能相结合的情况下。

结论

最初只是一个简单的问题——微软声称的Excel中Python的隔离性是否真的有效——却演变成一场漫长而多阶段的调查,最终揭露了微软Azure基础设施内部的合法root权限提升、对一项广泛使用的企业级功能底层容器镜像的未经身份验证的访问,以及绕过Excel自身客户端安全控制的方法。总而言之,这些发现提醒我们,云隔离声明理应受到安全团队对任何其他信任边界的同等严格审查,同时,人工智能功能快速集成到日常生产力工具中,也催生出许多需要持续密切关注的新领域。

为了帮助减轻这项研究中发现的漏洞可能造成的影响,我采取了以下措施:

  • 已按上述规定,分别于 2026 年 2 月 5 日和 2026 年 3 月 23 日向微软负责任地披露了所有调查结果。各组织应确保运行已打补丁的 Excel 版本。

  • 我在 DEF CON 34 (2026) 的演讲和这篇文章中与更广泛的安全社区公开分享了这项研究,以帮助使用 Microsoft 365 和 Excel 中的 Python 的组织更好地了解这些风险。

  • 在GitHub上发布了工具和研究资料,以支持社区的进一步研究。

https://github.com/SafeBreach-Labs/FromSquareRootToSlashRoot

END

公众号内容都来自国外平台-所有文章可通过点击阅读原文到达原文地址或参考地址

排版 编辑 | Ots 小安 

采集 翻译 | Ots Ai牛马

公众号 | AnQuan7 (Ots安全)