如何从黄金 gMSA 攻击中恢复

本文介绍修复受域控制器数据库泄露事件影响的组托管服务帐户(gMSA)的凭据的方法。

现象

有关 Golden gMSA 攻击的说明,请参阅以下 Semperis 文章:

黄金 GMSA 攻击简介

上述文章中的说明是准确的。 解决此问题的方法是替换Microsoft密钥分发服务(kdssvc.dll也称为 KDS)根密钥对象以及使用已泄露的 KDS 根密钥对象的所有 gMSA。

详细信息

在对 gMSA 的成功攻击中,攻击者获取 KDS 根密钥对象的所有重要属性以及 Sid gMSA 对象的和 msds-ManagedPasswordID 属性。

msds-ManagedPasswordID 属性仅存在于域的可写副本上。 因此,如果域控制器的数据库公开,则只有域控制器托管的域才对 Golden gMSA 攻击开放。 但是,如果攻击者可以向林中其他域的域控制器进行身份验证,攻击者可能有足够的权限来获取其 msds-ManagedPasswordID内容。 然后,攻击者可以使用此信息来针对其他域中的 gMSA 发起攻击。

若要在公开一个域后保护林的其他域,你必须替换公开域中的所有 gMSA,然后攻击者才能使用这些信息。 通常,你不知道所公开内容的详细信息。 因此,建议将解析应用于林的所有域。

作为主动措施,审核可用于跟踪 KDS 根密钥对象的公开情况。 可以将具有成功读取的系统访问控制列表(SACL)放置在主根密钥容器上,该容器允许审核对类属性msKds-ProvRootKey的成功读取msKds-RootKeyData。 此操作确定对象关于黄金 gMSA 攻击的暴露环境。

注意

审核仅有助于检测 KDS 根密钥数据的联机攻击。

可以考虑将 ManagedPasswordIntervalInDays 参数设置为 15 天,或者在创建 gMSA 时选择适当的值,因为 ManagedPasswordIntervalInDays 创建 gMSA 后该值变为只读。

如果遭到入侵,此设置可以减少下一个滚动时间。

如果坚持 方案 1,则会减少在还原备份日期与数据库泄露结束之间重新创建 gMSA 的理论数量,或者至少减少风险时段持续时间,直到这些 gMSA 滚动更新。

下面是一个示例场景:

  1. 数据库曝光后,可在“第 D 天”中执行恢复。

  2. 还原的备份来自 D-15。

    注意

    D-15 表示“第 D 天”之前的 15 天。

  3. gMSA ManagedPasswordIntervalInDays 值为 15。

  4. gMSA 存在并已滚动 D-1。

  5. 已从 D-10 创建较新的 gMSA。

  6. 妥协发生在 D-5 上,此时已创建一些 gMSA。

结果如下:

  1. D 和 D-5 之间创建的 gMSA 不相关*

  2. 必须在 D-15(已还原备份)和 D-5 之间创建 gMSA(泄露),* 或者,如果可以从 D+5 等待到 D+10,则必须假设风险窗口。 例如:

    • 在 D+5 上,必须在 D-10 上创建 gMSA。
    • 在 D+10 上,必须在 D-5 上创建 gMSA。

    *取决于泄露或备份的确切时间。

下面是一个示例时间线:

示例 gMSA 时间线图。

若要调试,可以查看系统、安全、目录服务和 Security-Netlogon 事件日志的事件 ID。

有关泄露的详细信息,请参阅 使用 Microsoft 和 Azure 安全资源来帮助从系统标识泄露中恢复。

解决方法

若要解决此问题,请使用以下方法之一,具体取决于你的情况。 这些方法涉及创建新的 KDS 根密钥对象并在域的所有域控制器上重启Microsoft密钥分发服务。

方案 1:你拥有有关公开哪些信息以及何时公开的信息的可靠信息

如果你知道暴露发生在某个日期之前,并且此日期早于你拥有的最旧 gMSA 密码,则可以在不重新创建 gMSA 的情况下解决问题,如下面的过程所示。

此方法是创建攻击者未知的新 KDS 根密钥对象。 当 gMSA 滚动更新其密码时,它们将移动到使用新的 KDS 根密钥对象。 若要修复最近使用旧 KDS 根密钥滚动更新其密码的 gMSA,需要授权还原才能在还原后立即强制更新密码。

注意

  • 无需手动修复在Active Directory 域服务(AD DS)数据库公开结束后创建的 gMSA。 攻击者不知道这些帐户的详细信息,这些帐户的密码将基于新的 KDS 根密钥对象重新生成。
  • 在过程完成之前,应考虑 gMSA 对象,并忽略系统、安全、目录服务和 Security-Netlogon 事件日志中帐户报告的可能错误。
  • 本指南假定 gMSA 是托管服务帐户容器的子对象。 如果已将帐户移动到自定义父容器,则需要在这些容器中的 gMSA 上运行与 托管服务帐户 容器相关的步骤。
  • 权威还原会将所有属性回滚到备份时的状态,包括允许检索 gMSA 凭据的帐户。PrincipalsAllowedToRetrieveManagedPassword

在保存要修复的 gMSA 的域中,执行以下步骤:

  1. 使域控制器脱机,并将其与网络隔离。

  2. 从 AD DS 数据库公开前创建的备份还原域控制器。

    如果 gMSA 的密码间隔时间长于备份的期限,则可以决定容忍以前的密钥材料仍然工作的窗口。 如果等待时间过长,并且匹配的旧备份缺少太多 gMSA,则需要将计划切换到 方案 2

  3. 对域的 托管服务帐户 容器运行权威还原操作。 请确保还原操作包括可能与此域控制器关联的所有容器的子对象。 此步骤回滚上次密码更新状态。 下次服务检索密码时,密码将基于新的 KDS 根密钥对象更新为新密码。

  4. 在还原的域控制器上停止和禁用Microsoft密钥分发服务。

  5. 在不同的域控制器上,按照“创建密钥分发服务 KDS 根密钥”中的步骤创建新的 KDS 根密钥对象。

    注意

    在生产环境中,需要等待 10 小时,以确保新的 KDS 根密钥可用。 检查属性 EffectiveTime 以了解新的 KDS 根密钥何时可用。

  6. 在所有域控制器上重启Microsoft密钥分发服务。

  7. 创建一个新的 gMSA。 确保新的 gMSA 使用新的 KDS 根键对象为 msds-ManagedPasswordID 属性创建值。

    注意

    此步骤是可选的,但它允许你验证新的 KDS 根密钥当前正在使用并在Microsoft密钥分发服务中使用。

  8. msds-ManagedPasswordID检查创建的第一个 gMSA 的值。 此属性的值是包含匹配 KDS 根密钥对象的 GUID 的二进制数据。

    例如,假定 KDS 根键对象具有以下 CN项。

    显示 KDS 根密钥对象的 CN 属性的值的屏幕截图。

    使用此对象创建的 gMSA 具有 msds-ManagedPasswordID 类似于以下内容的值。

    gMSA 对象的 msDS-ManagedPasswordId 属性的值的屏幕截图,其中显示了它如何包括 KDS 根键 CN 属性的片段。

    在此值中,GUID 数据从偏移量 24 开始。 GUID 的各个部分按不同的顺序排列。 在此图像中,红色、绿色和蓝色部分标识重新排序的部分。 橙色部分标识与原始 GUID 相同的序列部分。

    如果创建的第一个 gMSA 使用新的 KDS 根密钥,则所有后续 gMSA 也使用新密钥。

  9. 在所有域控制器上禁用和停止Microsoft密钥分发服务。

  10. 重新连接并将还原的域控制器重新联机。 确保复制正常工作。

    现在,将复制权威还原和所有其他更改(包括还原的 gMSA)。

  11. 在所有域控制器上重新启用并启动Microsoft密钥分发服务。 还原的 gMSA 的机密将滚动更新,并在请求时基于新的 KDS 根密钥对象创建新密码。

    注意

    如果 gMSA 已还原但未使用,并且已 PrincipalsAllowedToRetrieveManagedPassword 填充参数,则可以 Test-ADServiceAccount 使用允许检索密码的主体在还原的 gMSA 上运行 cmdlet。 如果需要密码更改,此 cmdlet 会将 gMSA 滚动到新的 KDS 根密钥。

  12. 验证是否已滚动更新所有 gMSA。

    注意

    未填充参数的 PrincipalsAllowedToRetrieveManagedPassword gMSA 永远不会滚动。

  13. 删除旧的 KDS 根密钥对象并验证复制。

  14. 在所有域控制器上重启Microsoft密钥分发服务。

方案 2:不知道 KDS 根密钥对象公开的详细信息,并且无法等待密码滚动更新

如果不知道公开了哪些信息,或者信息公开的时间,此类暴露可能是 Active Directory 林完整公开的一部分。 这可以创建攻击者可对所有密码运行脱机攻击的情况。 在这种情况下,请考虑运行林恢复或重置所有帐户密码。 将 gMSA 恢复到干净状态是此活动的一部分。

在以下过程中,必须创建新的 KDS 根密钥对象。 然后,使用此对象替换使用公开的 KDS 根密钥对象的林域中的所有 gMSA。

注意

以下步骤类似于组托管服务帐户入门中的过程。 但是,有一些重要的更改。

执行以下步骤:

  1. 禁用所有现有的 gMSA,并将其标记为要删除的帐户。 为此,对于每个帐户,请将属性设置为 4098(此值将WORKSTATION_TRUST_ACCOUNTACCOUNTDISABLE (禁用) 标志组合在一起)。userAccountControl

    可以使用如下所示的 PowerShell 脚本来设置帐户:

     $Domain = (Get-ADDomain).DistinguishedName
     $DomainGMSAs = (Get-ADObject -Searchbase "$Domain" -LdapFilter 'objectclass=msDS-GroupManagedServiceAccount').DistinguishedName
     ForEach ($GMSA In $DomainGMSAs)
     {
         Set-ADObject "$GMSA" -Add @{ adminDescription='cleanup-gsma' } -Replace @{ userAccountControl=4098 }
     }
    
  2. 使用单个域控制器并按照以下步骤操作:

    1. 按照“创建密钥分发服务 KDS 根密钥”中的步骤创建新的 KDS 根密钥对象。

    2. 重启Microsoft密钥分发服务。 重启后,服务会选取新对象。

    3. 备份与标记为要删除的每个 gMSA 关联的 DNS 主机名和服务主体名称(SPN)。

    4. 编辑现有 gMSA 以删除 SPN 和 DNS 主机名。

    5. 创建新的 gMSA 以替换现有的 gMSA。 还需要使用刚删除的 DNS 主机名和 SPN 来配置它们。

      注意

      还需要使用直接删除的 gMSA SID 查看所有权限条目,因为它们不再可解析。 替换访问控制项(ACE)时,请考虑使用组来管理 gMSA 权限条目。

  3. 检查新的 gMSA,确保它们使用新的 KDS 根密钥对象。 为此,请按照下列步骤进行操作:

    1. 记下 CN KDS 根密钥对象的 (GUID) 值。

    2. msds-ManagedPasswordID检查创建的第一个 gMSA 的值。 此属性的值是包含匹配 KDS 根密钥对象的 GUID 的二进制数据。

      例如,假定 KDS 根键对象具有以下 CN项。

      KDS 根密钥对象的 CN 属性值的屏幕截图。

      使用此对象创建的 gMSA 具有类似于 msds-ManagedPasswordID 图像的值。

      gMSA 对象的 msDS-ManagedPasswordId 属性的值的屏幕截图,其中显示了它如何包括 KDS 根键 CN 属性的片段。

      在此值中,GUID 数据从偏移量 24 开始。 GUID 的各个部分按不同的顺序排列。 在此图像中,红色、绿色和蓝色部分标识重新排序的部分。 橙色部分标识与原始 GUID 相同的序列部分。

      如果创建的第一个 gMSA 使用新的 KDS 根密钥,则所有后续 gMSA 也使用新密钥。

  4. 更新相应的服务以使用新的 gMSA。

  5. 使用以下 cmdlet 删除使用旧 KDS 根密钥对象的旧 gMSA:

    $Domain = (Get-ADDomain).DistinguishedName
    $DomainGMSAs = (Get-ADObject -Searchbase "$Domain" -LdapFilter '(&(objectClass=msDS-GroupManagedServiceAccount)(adminDescription=cleanup-gsma))').DistinguishedName
    ForEach ($GMSA In $DomainGMSAs)
    {
        Remove-ADObject "$GMSA" -Confirm:$False
    }
    
  6. 删除旧的 KDS 根密钥对象并验证复制。

  7. 在所有域控制器上重启Microsoft密钥分发服务。

方案 3:域管理员辞职,当时没有被盗信息,你可以等待密码滚动

如果具有域管理员或等效权限的特权成员辞职,则当时没有 KDS 根密钥泄露的证据,并且你可以为密码滚动提供时间窗口。 无需重新创建 gMSA。

作为预防措施,必须滚动 KDS 根密钥以防止任何利用后攻击。 例如,以前的域管理员原来是一个流氓,并保留一些备份。

创建新的 KDS 根密钥对象,gMSA 自然滚动。

注意

有关与域管理员相关的泄露,请参阅 方案 1方案 2 ,具体取决于已公开的内容,并遵循 “使用 Microsoft 和 Azure 安全资源来帮助从系统标识泄露中恢复”中的本地修正活动

在保存要滚动的 gMSA 的域中,执行以下步骤:

  1. 在域控制器上,按照“创建密钥分发服务 KDS 根密钥”中的步骤创建新的 KDS 根密钥对象。

    注意

    在生产环境中,需要等待 10 小时,以确保新的 KDS 根密钥可用。 检查属性 EffectiveTime 以了解新的 KDS 根密钥何时可用。

  2. 在所有域控制器上重启Microsoft密钥分发服务。

  3. 创建一个新的 gMSA。 确保新的 gMSA 使用新的 KDS 根键对象为 msds-ManagedPasswordID 属性创建值。

    注意

    此步骤是可选的,但它允许你验证新的 KDS 根密钥当前正在使用并在Microsoft密钥分发服务中使用。

  4. msds-ManagedPasswordID检查创建的第一个 gMSA 的值。 此属性的值是包含匹配 KDS 根密钥对象的 GUID 的二进制数据。

    例如,假定 KDS 根键对象具有以下 CN项。

    KDS 根密钥对象的 CN 属性值的屏幕截图。

    使用此对象创建的 gMSA 具有 msds-ManagedPasswordID 类似于下图的值。

    gMSA 对象的 msDS-ManagedPasswordId 属性的值的屏幕截图,其中显示了它如何包括 KDS 根键 CN 属性的片段。

    在此值中,GUID 数据从偏移量 24 开始。 GUID 的各个部分按不同的顺序排列。 在此图像中,红色、绿色和蓝色部分标识重新排序的部分。 橙色部分标识与原始 GUID 相同的序列部分。

    如果创建的第一个 gMSA 使用新的 KDS 根密钥,则所有后续 gMSA 也使用新密钥。

  5. 根据下一个密码滚动更新,gMSA 的机密自然会滚动,并且根据请求创建新的 KDS 根密钥对象创建新密码。

    注意

    如果使用的 gMSA 已滚动,但具有相同滚动间隔的未使用的 gMSA,并且已 PrincipalsAllowedToRetrieveManagedPassword 填充参数,则可以运行 Test-ADServiceAccount cmdlet。 它使用允许检索 gMSA 密码的主体,然后此步骤会将 gMSA 移动到新的 KDS 根密钥。

  6. 验证是否已滚动更新所有 gMSA。

    注意

    不带参数的 PrincipalsAllowedToRetrieveManagedPassword gMSA 永远不会滚动。

  7. 将所有 gMSA 滚动到新的 KDS 根密钥对象后,删除旧的 KDS 根密钥对象并验证复制。

  8. 在所有域控制器上重启Microsoft密钥分发服务。

参考

组托管服务帐户概述

第三方联系人免责声明

Microsoft 会提供第三方联系信息来帮助你查找有关本主题的其他信息。 此联系信息可能会更改,恕不另行通知。 Microsoft 不保证第三方联系信息的准确性。