小心轻放:串联AzureAutomation漏洞实现跨租户身份接管

admin 2026-08-23 04:46:59 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文档揭示了AzureAutomation服务中三个设计缺陷的串联攻击链,包括默认配置、路由Bug和正则表达式Bug,导致跨租户ManagedIdentity接管。攻击者可通过构造特殊请求绕过认证,获取目标租户资源访问权限。建议云安全工程师立即检查AutomationAccount配置并应用微软补丁。 综合评分: 90 文章分类: 漏洞分析,渗透测试,红队,云安全,安全建设


小心轻放:串联 Azure Automation 漏洞实现跨租户身份接管

原创

AIxSec69 AIxSec69

AIxSec69

2026年8月21日 17:02 美国

在小说阅读器读本章

去阅读

小心轻放:串联 Azure Automation 漏洞实现跨租户身份接管

来源:Black Hat USA 2026 Briefings

标题:Handle With Care: Chaining Azure Automation Flaws for Cross-Tenant Identity Takeover

作者:Shay Shavit,Microsoft 高级安全研究员

适合读者:云安全工程师、Azure 安全运维、红队/渗透测试人员、安全架构师

简介:演讲者展示了如何将 Azure Automation 服务中的多个设计缺陷串联起来——一个默认配置、一个路由 Bug、一个正则表达式 Bug——最终实现跨 Azure 租户的 Managed Identity 接管,获得对目标租户内 Key Vault、Storage、VM 等资源的访问权限。CVE-2025-29827,CVSS 9.9。

◆ ◆ ◆

Azure 是一个多租户云平台。租户(tenant)是最根本的隔离边界——你的资源、身份、密钥,理论上不应该被另一个租户的人碰到。如果这个边界被打破了,那就不是”某个服务配错了”的问题,而是云平台安全模型本身被凿开了一条缝。

Shay Shavit(Microsoft 安全研究员)在今年 Black Hat USA 上就展示了这样一条缝。他通过串联 Azure Automation 服务的三个缺陷,从一个攻击者自己拥有的租户出发,拿到了另一个完全无关租户的 Managed Identity token。本文是对该议题的技术解读。

Azure Automation 是什么

在展开攻击链之前,先理清 Azure Automation 涉及的核心组件:

– Runbook: PowerShell 或 Python 编写的自动化脚本,是用户定义”要做什么”的地方。

– Job: Runbook 的一次执行实例,可以按计划触发也可以手动触发。

– Worker: 执行 Job 的环境。可以是 Azure 托管的云沙箱(cloud sandbox),也可以是用户自己的混合 Worker(Hybrid Worker,运行在用户机器上并通过 Azure Arc 注册到 Automation Account)。

– Managed Identity(托管标识): Automation Account 关联的一个 Azure AD 身份,Runbook 用它来访问 Key Vault、Storage 等 Azure 资源,不需要在代码里硬编码密钥。

– JRDS(Job Runtime Data Service): Hybrid Worker 和 Automation Account 之间的通信桥梁。每个 Automation Account 有一个独立的 JRDS 端点(https://{accountId}.jrds.azure-automation.net),Worker 通过它获取 Job 信息、Notebook 内容,以及——关键的——Managed Identity token。

理解这些组件之间的关系之后,攻击链的逻辑就清晰了。

方法论:ANSR HUNTS CHAINS

Shavit 在演讲中先交代了他的研究方法,这不只是针对 Azure Automation 的”一次挖掘”,而是一套可复用的多租户威胁建模框架:

1. 枚举信任边界(Enumerate trust boundaries)——找出身份、租户、授权在哪个环节”换手”。

2. 串联间隙(Chain the gaps)——单一绕过往往不够,需要把多个原语(primitive)跨边界组合起来。

3. 在每个环节验证修复(Validate the fix at every link)——一个补丁从来不是”那个修复”,而是链条上每一个不安全假设都需要被消除。

这个方法论贯穿了整个研究过程。

失败的尝试也有价值

在一次安全研究中,走不通的路往往比走得通的路更值得讲——因为它告诉你,真正的边界在哪里。

Shavit 首先尝试了两条路,都没走通:

两条 SSRF。 在 Azure Automation 内部发现了两个服务端请求伪造(SSRF)点,但它们被限制在服务内部网络,无法触及跨租户的数据路径。

RCE(沙箱化)。 通过 Python Package 上传拿到了代码执行能力,但执行环境是一个沙箱(sandbox),无法突破到目标租户。

这些失败尝试传递了一个信号:当你发现一个 Bug 无法串联到更大的攻击链时,回头审视你到底需要跨过哪条边界。 在本案例中,那条边界就是 JRDS 的认证逻辑。

Python Package 上传:第一次穿透信任边界

Azure Automation 允许用户上传 Python Package(.whl 格式)到自己的 Automation Account,以便 Runbook 在运行时导入使用。

上传流程是这样的:用户上传 .whl 文件 → 服务端进行 Package Validation → 存入 Automation Account 的 Package Store。Validation 这一步是关键——它发生在一个共享的服务环境中,处理的是用户提供的”不可信输入”。

Validation 内部做了三件事:

  1. 解压 Archive

  2. 读取 Wheel Metadata

  3. 调用 pip 命令

第三步实际执行的命令大致为:

pip.exe install --root C:/temp/{random}/ --ignore-installed --no-deps --ignore-requires-python {wheelFilePath}

问题出在 pip 的参数可以被 Wheel 包内的 metadata 控制。攻击者可以构造一个特殊的 .whl 包,让 pip 安装时通过 -r 参数指向攻击者控制的地址,从而实现代码执行。

虽然在沙箱内实现了代码执行,而且沙箱确实能获取当前 Automation Account 的 Managed Identity token,但 Shavit 试图让沙箱去请求另一个 Account 的 MI token 时,这条路被封死了。

不过这次尝试暴露了一个关键信息:Automation 服务内部有一个机制,能够为所有 Automation Account 获取 Managed Identity token。 这意味着——如果你能找到另一个向量来触发这个机制,就有可能拿到别人的 token。

JRDS 认证的三个 Gate

Hybrid Worker 和 JRDS 之间的认证过程由三个 Handler 组成,按顺序执行。如果当前 Handler 认证失败,下一个会继续尝试:

  1. CertificateHandler —— 证书认证

  2. JwtHandler —— JWT 认证

  3. MIHandler —— Managed Identity 专用认证

其中 JwtHandler 内部又分为三道检查(Gate),每道 Gate 回答一个不同的问题:

Gate 1:验证 JWT 有效性

“你拿着的 token 是有效的吗?”

攻击者需要提供一个有效的 Managed Identity JWT。这个 JWT 来自攻击者自己租户内的一个合法 VM 的 Managed Identity。Gate 1 只校验 token 本身是否有效——不关心它属于哪个 Automation Account。

通过。

Gate 2:绑定身份到 VM

“token 代表的身份和请求里的 VM 是同一个吗?”

请求中包含一个查询参数 ?vmResourceId={VM资源ID}。Handler 会检查 JWT 中的 Managed Identity 是否属于 vmResourceId 指定的 VM。

关键洞察:vmResourceId 是请求中攻击者自己提供的参数。 攻击者只需要让自己的 JWT(来自自己的 VM)和 vmResourceId(也指向自己的 VM)匹配即可。

通过。

Gate 3:查询 Worker 关联信息

“这个 Worker 和请求的目标 Automation Account 有关系吗?”

这是最关键的一道 Gate——它应该确保请求者(Worker)已经注册为所请求 Automation Account 的 Hybrid Worker。正常情况下,你只能在你自己注册过的 Account 里操作。

但问题出在这里:

if (!IsLocation(request)){

AssociateWorker();

}

private bool IsLocation(HttpRequestMessage request)

{

return request.RequestUri.AbsoluteUri.Contains("location");

}

IsLocation() 检查请求 URI 是否包含字符串 "location"。如果包含,就跳过 Worker 关联检查。

AbsoluteUri 包含查询参数。所以攻击者只需要在请求参数里加一个 &location

GET /automationAccounts/{victimAccount}/action?vmResourceId={attackerVm}&location

关联检查就被绕过了。

▲ 绕过关联检查后暴露的攻击面:证书签名材料、认证材料、服务凭据、secrets、Notebook 内容与 Job 结果(来源:Black Hat USA 2026 Slides)

Gate 3——被绕过了。

tokeN:一个字符的差距

绕过 JRDS 认证后,攻击者的目标是获取目标 Automation Account 的 Managed Identity token。获取 token 的端点是:

GET /automationAccounts/{accountID}/oauth2/token

但直接请求这个端点会返回 403 Forbidden。原因是 JwtHandler 中有一段逻辑:

if (IsMIRequest(request.uri))

{

// Skip Auth Token based authentication

return base.Send(request);

}

IsMIRequest() 通过正则表达式匹配 /automationAccounts/{guid}/oauth2/token。如果匹配成功,JwtHandler 就跳过,把请求交给下一个 Handler——MIHandler。

MIHandler 需要 Automation Account 内部的一个 per-account secret 才能完成认证。攻击者没有这个 secret,也无法从前面的绕过路径中获取它。

但”Handler 是按顺序执行的,一个失败就试下一个”这条规则给了机会。

JwtHandler 在 MIHandler 之前执行。如果能让 JwtHandler 不跳过,它就能用攻击者的 JWT 完成认证,然后请求就不会再走到 MIHandler。

突破口就在这里:

/oauth2/token → IsMIRequest() 匹配成功 → JwtHandler 跳过 → MIHandler 接管 → 403

/oauth2/tokeN → IsMIRequest() 匹配失败 → JwtHandler 执行认证 → 通过 → 200

一个字符的大小写差异,决定了走哪条认证路径。 Handler 层面的正则匹配是大小写敏感的,但 ASP.NET 的路由控制器(Controller)是大小写不敏感的。同一个端点 /oauth2/tokeN,Handler 层认为它不是 MI 路由所以走 JWT 认证,Controller 层照样把它路由到 token 生成逻辑。

这就是 CVE-2025-29827 的核心。

完整攻击链

▲ 攻击链总览:攻击者租户的 Account/Hybrid Worker VM/MI → JRDS 端点 → 受害者租户的 Account/MI(来源:Black Hat USA 2026 Slides)

将上述所有组件串联起来,形成了一条完整的跨租户攻击链(7 步):

Step 1 —— 合法起点。 攻击者在自己的租户内拥有一个合法的 Azure Automation Account、Hybrid Worker VM 和 Managed Identity。一切从这里开始。

Step 2 —— 公开目标。 Automation Account 默认对互联网开放。攻击者可以访问目标(受害者)Automation Account 的 JRDS 端点。

▲ 攻击链 Step 3:跨账户 JRDS 请求,目标指向受害者 Account(来源:Black Hat USA 2026 Slides)

Step 3 —— 跨账户 JRDS 请求。 攻击者构造请求,目标指向受害者账户:

GET /automationAccounts/{victimAccount}/.../?vmResourceId={attackerVm}

Step 4 —— 身份形状校验通过。 Gate 1(有效 JWT)和 Gate 2(JWT 身份匹配 vmResourceId)均通过,因为它们只检查攻击者身份的”形状”,不检查归属。

Step 5 —— 关联检查绕过。 在请求参数末尾追加 &location,Gate 3 的 IsLocation() 检查触发,Worker 关联校验被跳过。

Step 6 —— Token 路由错配。 请求目标改为 /oauth2/tokeN(大写 N)。JwtHandler 的正则不匹配,走 JWT 认证流程并成功;路由控制器将请求分发到 token 生成端点。

Step 7 —— 获取受害者 Managed Identity。 攻击者拿到受害者 Automation Account 的 Managed Identity token。通过这个 token,攻击者可以访问受害者租户内该 Managed Identity 有权访问的所有 Azure 资源——Key Vault、Storage、VM、Subscription 等。具体能做什么取决于该 Managed Identity 的角色分配,而大多数 Automation Account 的 Managed Identity 都拥有 Contributor、Owner 等高权限角色。

修复:打断每一条链

微软的修复不是一个补丁,而是针对链条上的每一个不安全假设分别加固:

| 链接 | 弱点 | 修复 |

|——|——|——|

| Link 1 | Automation Account 默认公开 | 引导用户启用 Private Endpoint |

| Link 2 | Worker 关联检查可被 query 参数绕过 | 对请求参数做规范化(normalize)和严格校验后再进行关联查询 |

| Link 3 | Handler 大小写敏感 vs Controller 大小写不敏感 | 统一 Handler 路由和 Controller 路由的匹配规则 |

| Link 4 | Token 签发时缺少再次授权校验 | 在 token 生成边界重新校验授权 |

核心思路是:不要只封堵一个 Bug,而要消除链条上每一个环节中不安全的设计假设。

检测:你不需要抓到 Bug,你需要抓到模式

Shavit 在演讲最后给出了三条检测建议,重点不是去匹配漏洞本身,而是去捕获攻击模式:

1. 异常的 JRDS 访问。 监控调用者租户 ID 与目标 Automation Account 所属租户不一致的 JRDS 请求。跨租户的 Hybrid Worker 注册不是合法行为模式。

2. Token 端点的可疑查询参数。 关注请求 /automationAccounts/\*/oauth2/token\* 中包含 &location、大小写混用(如 tokeNToken)或尾部多余字符的情况。这条攻击链中的两个绕过原语在 URI 层都是可见的。

3. 无 Worker 关联的 Managed Identity token 签发。 监控 Managed Identity token 被签发给没有注册为该 Account Hybrid Worker 的调用者。这是”接管”发生的时刻——如果只能抓到一条,就抓这条。

总结

这个案例的价值远不止于 Azure Automation 这一个服务。它展示了一种适用于所有多租户云服务的威胁建模思路:

– 枚举信任边界,找到身份和授权”换手”的地方。

– 攻击每一道 Gate,看看它到底在验证什么——是”身份的形状”还是”身份的归属”。

– 串联间隙,把看似独立的低危问题组合成高危攻击链。

– 验证修复的每一环——一个补丁不是”那个修复”,链条上每一个不安全假设都必须消除。

默认公开 + 参数校验绕过 + 大小写路由错配,三个看似不起眼的问题串联起来就是 CVSS 9.9 的跨租户身份接管。云安全隔离的强度,取决于服务间信任假设中最弱的那一环。

原文链接:https://www.blackhat.com/us-26/briefings/schedule/#handle-with-care-chaining-azure-automation-flaws-for-cross-tenant-identity-takeover-53966


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:AIxSec69 AIxSec69 AIxSec69《小心轻放:串联 Azure Automation 漏洞实现跨租户身份接管》

评论:0   参与:  0