BadSuccessor:在 Active Directory 环境中滥用 dMSA 发动提权攻击
内容提要
Akamai 研究人员 Yuval Gordon 在 Windows Server 2025 中发现了一个特权提升漏洞,攻击者利用该漏洞可以入侵 Active Directory (AD) 中的任何用户帐户。
该攻击利用了 Windows Server 2025 中引入的委派托管服务帐户 (dMSA) 功能。此攻击在默认配置下即可生效,且实现过程极其简单。
此问题可能会影响大多数依赖 AD 的企业。我们的分析发现,在 91% 的环境中,存在非域管理员用户拥有可执行此攻击权限的问题。
虽然 Microsoft 表示他们计划在未来修复此问题,但目前没有可用的补丁。因此,企业需要采取其他主动措施来降低遭受此攻击的风险。Microsoft 已审查了我们的发现结果并同意公布此信息。
在本博文中,我们将提供此攻击的完整细节以及检测和抵御策略。
目录
前言
在 Windows Server 2025 中,Microsoft 引入了委派托管服务帐户 (dMSA) 功能。dMSA 是 Active Directory (AD) 中的一种新型服务帐户,用于扩展组托管服务帐户 (gMSA) 的功能。dMSA 的一项主要功能是,它能够通过将现有的非托管服务帐户无缝转换为 dMSA 来迁移这些帐户。
在探究 AD 的 dMSA 的内部运作机制时,我们意外地发现了一些有意思的东西。乍一看,迁移机制似乎是一种简洁且经过精心设计的解决方案。但其底层的运作机制引起了我们的注意。
随着我们的深入探究,我们发现了一条令人惊讶的升级路径:通过滥用 dMSA,攻击者可以接管域中的任何主体。攻击者只需要拥有对域中任何组织单元 (OU) 的无害权限即可执行此攻击,而该权限往往并不引人注意。
而最重要的是:该攻击默认情况下是有效的——您的域根本不需要使用 dMSA。只要该功能存在(至少在具有一个 Windows Server 2025 域控制器 (DC) 的任何域中存在),它便可供使用。
本博文将介绍我们发现此问题的过程、攻击的运作方式以及您可以采取哪些措施来检测或阻止它。
什么是 dMSA?
在深入研究攻击之前,有必要了解一下 dMSA 是什么以及它们应如何运作。
dMSA 通常是为了替换现有的旧服务帐户而创建的。为了实现顺利过渡,dMSA 可以通过执行迁移过程来“继承”旧帐户的权限。此迁移流程将 dMSA 与被取代的帐户(即,它们要取代的原始帐户)紧密关联在一起。该流程以及它在此过程中授予的权限让事情变得有趣起来。
dMSA 迁移流程
dMSA 的迁移过程可以通过调用新的 Start-ADServiceAccountMigration cmdlet 来触发。在内部,它会调用名为 migrateADServiceAccount 的新 LDAP rootDSE 操作,该操作将使用以下参数:
dMSA 的专有名称 (DN)
被取代帐户的 DN
对应于 StartMigration 的常量
dMSA 的迁移状态由 msDS-DelegatedMSAState 属性决定,该属性是用于确定 dMSA 当前状态的新属性。目前,没有关于 msDS-DelegatedMSAState 属性的官方文档,因此下表基于我们自己的行为分析和实验。
值 |
含义 |
0 |
位置(可能已禁用,但未经确认) |
1 |
迁移正在进行中 |
2 |
迁移已完成 |
3 |
独立 dMSA(无迁移) |
msDS-DelegatedMSAState 迁移值和相关含义
除了此属性之外,迁移过程中还使用了其他一些值得注意的属性。
在 dMSA 对象上:
msDS-GroupMSAMembership:包含有权使用此 dMSA 的主体的列表
msDS-ManagedAccountPrecededByLink:被取代帐户的 DN
在被取代的帐户对象上:
msDS-SupersededManagedAccountLink:“继任的”dMSA 的 DN
msDS-SupersededServiceAccountState:与 msDS-DelegatedMSAState 的含义相同,指定原始帐户迁移状态
触发迁移时,该操作会进行以下更改:
将 msDS-DelegatedMSAState 设置为 1(迁移正在进行中)
更新 dMSA 的 ntSecurityDescriptor,以便向被取代的帐户授予:
读取权限
对 msDS-GroupMSAMembership 属性的写入权限
设置 dMSA 的 msDS-ManagedAccountPrecededByLink 以引用被取代的帐户
设置被取代帐户的 msDS-SupersededManagedAccountLink 以引用 dMSA
将被取代帐户的 msDS-SupersededServiceAccountState 设置为 1
此时,dMSA 处于“迁移正在进行中”状态。它尚无法完全正常工作,但现在知道哪些系统仍在使用旧的服务帐户。
在发出 Complete-ADServiceAccountMigration 命令后,系统将进行以下操作:
dMSA 会从被取代帐户继承关键配置,例如 SPN、委派设置以及其他敏感属性
被取代的帐户将被禁用
msDS-DelegatedMSAState 和 msDS-SupersededServiceAccountState 都被设置为 2(迁移已完成)
迁移完成,并且依赖被取代帐户的任何服务现在将使用 dMSA 进行身份验证。
dMSA 身份验证
现在,我们了解了 dMSA 的创建和迁移过程,接下来我们将重点关注身份验证的运作机制、为支持 dMSA 而引入的更改,以及这些更改如何使迁移过程顺利进行。
为了便于理解,我们来检查 svc_sql legacy 服务帐户,该帐户用于在 SQL_SRV$ 服务器上运行服务。每当需要该服务来访问域中的资源时,系统都会使用 svc_sql 帐户进行正常身份验证(图 1)。
迁移过程中的身份验证
现在,我们将服务帐户转换为名为 DMSA$ 的新 dMSA,并触发迁移。在迁移过程中,当 SQL_SRV$ 上的服务以 svc_sql 身份进行身份验证时,身份验证流程会略有修改。
客户端会发送 AS-REQ 来以 svc_sql 身份进行身份验证
密钥发行中心 (KDC) 将返回包含一个附加字段的 AS-REP:KERB-SUPERSEDED-BY-USER(此字段包含新 dMSA DMSA$ 的名称和领域)
如果主机支持 dMSA(Windows Server 2025 或 Windows 11 24H2)并且已启用 dMSA 身份验证,则它将:
提取 DMSA$ 名称
对 DMSA$ 执行 LDAP 查询,以检索下列属性:
msDS-GroupMSAMembership
distinguishedName
objectClass
由于服务是以 svc_sql 身份在 SQL_SRV$ 上运行的,因此身份验证本身会触发来自 svc_sql 的 LDAP 修改请求,该请求会将 SQL_SRV$ 添加到被允许检索 DMSA$ 的密码的主体列表中(图 2)。
这是可以实现的,因为在迁移过程中,svc_sql 被授予了对 dMSA 上 msDS-GroupMSAMembership 属性的写入权限,此更改使其能够授权其主机访问该帐户的凭据。
这种无缝的权限授予可确保在迁移完成时,先前使用 svc_sql 的每台机器都会被列入 DMSA$ 的 msDS-GroupMSAMembership 属性中,从而使其能够以 dMSA 身份进行身份验证。
迁移完成后的身份验证
迁移通过 Complete-ADServiceAccountMigration 完成后,行为会再次发生变化。
当客户尝试通过发送 AS-REQ 来以 svc_sql 身份进行身份验证时,它不再接收 AS-REP
DC 会改为以 KRB-ERROR 进行响应,表明 svc_sql 已被禁用
KRB-ERROR 将包含 KERB-SUPERSEDED-BY-USER 字段,使客户端能够识别 svc_sql 已完成迁移并使用 DMSA$ 自动重试身份验证(图 3)。
SQL_SRV$(和先前依赖 svc_sql 的任何其他机器)现在将透明地切换为使用 DMSA$。
出乎意料的行为
dMSA Kerberos 身份验证的一个有意思的方面涉及其特权属性证书 (PAC)。
进行身份验证时,Kerberos 会将一个 PAC 嵌入到票证中——这是服务用于确定客户端访问级别的一种结构。在标准的票证授予票证 (TGT) 中,PAC 包含用户及其所属的所有组的 SID。
但是,使用 dMSA 登录时,我们观察到了意外的情况。
PAC 不仅包含了 dMSAs SID,还包含了被取代的服务帐户及其所有关联组的 SID。
滥用 dMSA 迁移过程以实现特权提升
进行迁移后,KDC 会向 dMSA 授予所有原始(被取代的)帐户的权限。
从设计角度看,这合情合理。其目的是提供无缝的迁移体验,使新帐户的行为与它所取代的帐户完全一致——相同的 SPN、相同的委派、相同的组成员身份。
但是,从安全研究人员的角度看,此类行为会立即引起注意。当看到无需手动重新配置就能自动将特权从一个帐户复制到另一个帐户的系统时,我们便开始进行深入调查:它是如何决定要从哪个帐户进行复制的?这会受到影响吗?它是否会遭到滥用?
这一连串的疑问引领我们取得了重大发现。PAC 继承的这种有趣行为似乎由单个属性控制:msDS-ManagedAccountPrecededByLink。
KDC 依赖此属性来确定 dMSA 将“取代”的帐户——当 dMSA 进行身份验证时,PAC 完全基于此链接进行构建。
是时候像攻击者一样思考了
从攻击者的角度看,这又是什么样子呢?我们来探讨一种可能的攻击场景,看看攻击者利用此功能可以实现什么目标。
我们的第一个想法是:使用 dMSA 来创建一个帐户接管的原语。如果我们假设自己拥有对某个用户帐户的权限,那么是否能够以某种方式将其权限“迁移”到新的 dMSA 来隐蔽地入侵该帐户?这似乎是一个切实可行的方法。我们要做的就是:
创建一个 dMSA
使用 migrateADServiceAccount rootDSE 操作启动并完成目标用户与 dMSA 之间的迁移
以 dMSA 身份进行身份验证,获取目标用户的所有权限
唯一的问题是:此方法行不通。
即使我们完全控制了 dMSA 和被取代的帐户,我们也无法执行迁移,因为据我们所知,migrateADServiceAccount 操作只能由域管理员执行。图 4 显示了失败尝试的示例。
接下来,我们将检验另一种可能性。显然,我们需要的是复杂、有创意并且技术含量高的方法。我们需要探索那些未公开的行为,甚至可能需要对 KDC 的某些部分进行逆向工程……或者我们可以只设置两个属性。
虽然我们无法直接执行迁移,但可以通过直接在 dMSA 对象上设置以下属性来轻松“模拟”迁移。
将目标帐户的 DN 写入 msDS-ManagedAccountPrecededByLink
将 msDS-DelegatedMSAState 设置为值 2(迁移已完成)
从现在开始,每次我们以 dMSA 身份进行身份验证时,KDC 都会使用 msDS-ManagedAccountPrecededByLink 属性中关联帐户的 SID 构建 PAC,从而可以有效地向我们授予被取代帐户的全部权限。
BadSuccessor 简介
关于这个“模拟迁移”技术,一个有趣的事实是:它完全不需要对被取代的帐户拥有任何权限。唯一的要求是拥有对 dMSA 的属性的写入权限。任何 dMSA。
在我们将 dMSA 标记为某个用户的迁移目标后,KDC 便会自动假定发生了合法迁移,并自动向我们的 dMSA 授予原始用户所拥有的每一项权限,就好像我们是其合法继承者一样。
但是,这对高权限帐户肯定不起作用,对吧?这个……
此外,此方法我们称之为“BadSuccessor”,适用于任何用户,包括域管理员(图 5)。它允许控制 dMSA 对象的任何用户控制整个域。这就足够了。没有实际的迁移。不需要验证。不受监督。
利用 dMSA:从低级特权到域名控制
这时,您可能会想,“好吧,我没有在自己的环境中使用 dMSA,所以这不会影响到我”。事实可能并非如此。
一种滥用场景:攻击者获得了对某个现有 dMSA 的控制权,并利用此权限执行 BadSuccessor 攻击。但是,实际上还有攻击者可能会更频繁地使用的另一种场景:攻击者创建新的 dMSA。
当用户在 AD 中创建对象时,他们拥有对其所有属性的全部权限。因此,如果攻击者可以创建新的 dMSA,他们便能够入侵整个域。
通常,如果 dMSA 是使用 New-ADServiceAccount cmdlet 创建的,它会存储在托管服务帐户容器中。虽然用户可以被授予对此容器的访问权限,但默认情况下,只有内置的特权 Active Directory 组才拥有对它的权限。因此,我们能够对此容器执行写入操作的可能性不大。
然而,dMSA 并不局限于托管服务帐户容器;也可以在任何普通的 OU 中创建它们。在任何 OU 上拥有创建 msDS-DelegatedManagedServiceAccount 权限或创建所有子对象权限的任何用户都可以创建 dMSA。
创建 dMSA
允许用户在 OU 中创建对象是一种很常见的配置。由于这种能力被视为一项无害功能,因此拥有此特权的用户不太可能会受到适当的监控和严格的约束。
要创建 dMSA,我们首先要找到一个我们拥有相关特权的 OU。幸运的是,有人已经在我们的示例环境中创建了名为“temp”的 OU,并向我们的非特权用户赋予了“弱”权限来创建所有子对象(图 6)。
然后,我们可以使用这些权限通过 New-ADServiceAccount cmdlet 创建 dMSA。正如图 7 所示,虽然非特权用户无法在默认的 MSA 容器中创建 dMSA,但我们可以使用路径参数在可访问的 OU 中创建 dMSA。
现在,我们很高兴成为了新创建但无法正常工作的 dMSA 的所有者。作为创建者所有者,我们可以向自己授予对该对象的权限,包括对我们将用于此攻击的两项属性的写入权限,然后我们可以通过以下方式修改这些属性:
msDS-ManagedAccountPrecededByLink:将此属性设置为任何用户或计算机的 DN——域控制器、域管理员组的成员、受保护的用户,甚至是(具有讽刺意味)被标记为“帐户敏感且无法委派”的帐户
msDS-DelegatedMSAState:将此属性设置为 2,以模拟已完成的迁移(图 8)
正如我们先前提到的,此攻击似乎对 AD 中的所有帐户有效。我们找不到任何能够阻止某个帐户被用作取代目标的配置。
获取 dMSA 的 TGT
使用我们的 dMSA 进行身份验证的一种方法是创建一项服务,并将其配置为使用 dMSA 帐户执行。这可以实现,但不太方便。幸运的是,多亏了 Joe Dibley 出色的拉取请求,Rubeus 现在支持 dMSA 身份验证(图 9),这意味着我们可以用它请求获取我们 dMSA 的 TGT:
Rubeus.exe asktgs /targetuser:attacker_dmsa$ /service:krbtgt/aka.test /dmsa /opsec /nowrap /ptt /ticket:<Machine TGT>
dMSA → 域管理员
对于此示例,我们以内置的管理员帐户为目标。通过使用 Wireshark,我们检查了收到的 dMSA 票证的 PAC(图 10),其中包含:
dMSA 的 RID (1137)
被取代帐户的 RID(500 — 管理员)
被取代帐户的所有组成员身份(512 — 域管理员,519 — 企业管理员)
这就是域控制器将我们视为合法继承者所需要的一切。请记住:无需更改组成员身份,无需借助域管理员组,也无需对实际特权帐户进行可疑的 LDAP 写入。
只需更改两项属性,一个不起眼的新对象便会被加冕为继承者——KDC 不会对先前链接的合法性进行验证;只要链接存在,就会授予特权。我们没有更改任何一个组成员身份,没有升级任何现有帐户,也没有触发任何传统的特权提升告警。
演示:端到端攻击流
观看此视频,了解实际攻击的完整演示。
关于如何在 Active Directory 环境中滥用 dMSA 发动提权攻击的演示
别急,还没完——滥用 dMSA 来窃取凭据
搞到任意我们想要的用户的 TGT 固然很酷,但我们想要的不止于此。要是我们还想要他们的凭据呢?幸运的是,在这种情况下,dMSA 同样能为我们所用。
当您请求获取 dMSA 的 TGT 时,它会附带一个称为 KERB-DMSA-KEY-PACKAGE 的新结构。此结构包含两个字段:current-keys 和 previous-keys。根据 MSDN 的说法,这两个字段应该包含与 dMSA 当前和先前的密码相关的密钥——事实也确实如此。但这还不是事实的全部。
我们很惊讶地发现,即使在请求获取新创建的 dMSA 的 TGT 时,previous-keys 字段也不为空。由于它是刚创建的,因此不应该存在“先前的密码”。我们忽略了这一事实,直到我们意识到有些东西看起来非常眼熟。
如图 11 所示,结构中的第二个元素包含一个类型为 23 的密钥 (RC4-HMAC)。此加密类型未进行加盐处理,这意味着相同的密码会生成相同的密钥,即使在不同用户之间也是如此。
那么这个特定的密钥呢?多年来在实验环境中重复使用同一密码的做法,如今终于“见效”了。我们一眼便认出了它。它是与我们在演示期间用于目标帐户的密码 Aa123456 相对应的密钥。
我们来思考一下:某个单独帐户的密钥以某种方式最终进入了 dMSA 的 previous-keys 结构中。
大规模泄露密钥
那么,这里发生了什么?原因又是什么?
msDS-ManagedAccountPrecededByLink 不仅仅将 dMSA 与被取代的帐户相关联以获取权限,它还让 dMSA 继承了其密钥。这意味着,此攻击还可用于获取域中任何(或每个)用户及计算机的密钥。我们可以使用此密钥对帐户进行身份验证。
虽然我们未分析整个实施过程,但我们的看法是,此行为之所以存在是为了确保帐户迁移期间的无缝连续性,从而使最终用户受益。
假设我们有一项使用旧服务帐户运行的服务。域中的帐户都会向此服务请求票证,这些票证使用旧服务帐户的密钥进行加密。现在,假设我们将该旧帐户替换为 dMSA,迁移已完成,并且服务帐户已替换为 dMSA,但 dMSA 无权访问旧帐户的密钥。
结果:当客户端尝试使用其现有票证进行身份验证时,服务器无法使用新的 dMSA 密钥对其进行解密,这导致所有已签发的票证无法使用,即使它们未过期也是如此。
为了避免出现此类服务中断,KDC 在新 dMSA 的密钥包结构中包含了先前帐户的密钥,并将它们视为 dMSA 先前的凭据,从而使其能够对“旧”票证进行解密。
在我们明白了这一点之后,另一个奇怪的现象就开始变得合理了。current-keys 字段包含三个元素,其中每个元素都由一个整数(表示加密类型)和一个八位字节字符串(相应的密钥)组成。您可以参阅此页面以了解加密类型值。在我们的示例中,列表包含 RC4-HMAC、AES256 和 AES128 的密钥。但是,previous-keys 字段看起来稍有不同,它只包含一个对应于 RC4-HMAC 的密钥(图 12)。为什么 previous-keys 列表只包含一种密钥类型,并且具体而言,为什么它是 RC4-HMAC?
答案在于原始(被取代的)帐户所支持的加密类型。服务票证仅使用目标服务支持的加密类型进行加密。正如 Harmj0y 的精彩博文中所解释的那样,msDS-SupportedEncryptionTypes 属性可控制此行为。如果此属性未定义(用户帐户的默认情况),则系统默认仅使用 RC4-HMAC,因此 previous-keys 列表中只有一个 RC4-HMAC 密钥。
换句话说,KDC 仅向 dMSA 提供原始帐户中的密钥,这些密钥是对迁移前所签发的服务票证进行解密所必需的。这些密钥是根据原始主体支持的加密类型确定的,您可以通过检查其 msDS-SupportedEncryptionTypes 属性来进行验证。
Microsoft 的回应
我们于 2025 年 4 月 1 日通过 MSRC 向 Microsoft 报告了这些详细信息。在审查了我们的报告和概念验证之后,Microsoft 承认了此问题并确认了其有效性。然而,他们将其评估为中等严重程度的漏洞,并表示该漏洞目前未达到进行立即修复的门槛。
Microsoft 表示,成功利用该漏洞需要攻击者已拥有 dMSA 对象的特定权限,而这一前提条件本身即表明攻击者拥有的权限已得到提升。针对创建新 dMSA 的场景,Microsoft 引用了 KB5008383,该文章中讨论了与 CreateChild 权限相关的风险。
虽然我们感谢 Microsoft 作出回应,但我们不敢苟同其严重性评估。
此漏洞会带来一个先前未知并且会产生重大影响的滥用路径,此路径使得 OU 上任何拥有 CreateChild 权限的用户都能够入侵域中的任何其他用户帐户,并获得与用于执行 DCSync 攻击的复制目录更改特权类似的权力。
此外,我们还发现,没有任何迹象表明当前的行业实践或工具将 CreateChild 访问权限(或者,更具体地来说,dMSA 的 CreateChild)标记为严重问题。我们认为,这凸显出了此问题的隐蔽性和严重性。
检测和抵御
检测
要检测此攻击媒介的潜在滥用问题,企业应重点关注以下几个方面:
审核 dMSA 创建——配置一个 SACL 来记录新 msDS-DelegatedManagedServiceAccount 对象的创建事件(事件 ID 5137;图 13)。应特别注意通常不负责进行服务帐户创建的帐户。
监控属性修改——配置一个 SACL 来记录 msDS-ManagedAccountPrecededByLink 属性的修改事件(事件 ID 5136;图 14)。对此属性的更改是尝试或成功进行滥用的强烈信号。
跟踪 dMSA 身份验证——当为 dMSA 生成了 TGT,并且它包含 KERB-DMSA-KEY-PACKAGE 结构时,域控制器会记录事件 ID 2946(目录服务日志)。
组托管服务帐户对象字段(虽然这是 dMSA 而不是 gMSA)将显示正在进行身份验证的 dMSA 的 DN,并且调用方 SID 字段将显示为 S-1-5-7(图 15)。应当对频繁或意外出现涉及异常 dMSA 的 2946 事件进行调查。
审查权限——密切关注 OU 和容器的权限。过于宽松的委派会为此类滥用大开方便之门。
抵御措施
在 Microsoft 发布正式补丁之前,防御措施应侧重于限制创建 dMSA 的能力并尽可能严格控制权限。
防御者应识别域中所有有权创建 dMSA 的主体(用户、组、计算机),并将其限制为只能由受信任的管理员创建。
为此,我们发布了一个 PowerShell 脚本,该脚本可以:
枚举能够创建 dMSA 的所有非默认主体
列出每个主体在哪些 OU 中拥有此权限
Microsoft 已通知我们,他们的工程团队正在开发补丁。在获得更多的技术细节后,我们将在本博文中更新抵御指南。
结论
本研究凸显出,在 Active Directory 环境中,即使是通常被认为风险较低的狭义权限,也会产生深远的影响。攻击者的创造力不容小觑。如果说最近的技术进步教会了我们什么,那就是看似无害的功能也可能会造成严重后果。dMSA 原本是作为一种现代化的服务帐户管理解决方案引入的,但它的出现也带来了新的复杂性,以及随之而来的新的滥用机会。
企业应该像对待其他敏感操作一样,对创建 dMSA 或控制现有 dMSA 的能力进行同等程度的审查。应当严格限制管理这些对象的权限,并且应当定期监控和审核对这些对象的更改。
我们希望通过这项研究揭示 Windows Server 2025(特别是 dMSA)带来的普遍风险,并帮助防御者更好地理解和减轻错误配置的权限可能造成的影响。