滥用ADCS进行权限提升—ESC13详解

本文首发于先知社区:https://xz.aliyun.com/t/13864

0x1 起因:

​ 自 Will Schroeder(@harmj0y)和 Lee Christensen(@tifkin_)在 2021 年的 BlackHat 大会上发布白皮书以来,ADCS的攻击面首次系统化的进入人们的视野。Certified Pre-Owned - Abusing Active Directory Certificate Services这本白皮书可以说是为ADCS的利用奠定了各种理论基础。
​ 随着ADCS的利用越加广泛,各种工具层出不穷,其中Certipy更是其中的佼佼者,近日在学习Certipy的相关代码实现的时候,偶然发现了这样一条PR

众所周知(应该),在白皮书中一共介绍了ESC1-ESC8这8种ESC命名的攻击手法,后续又补充了Oliver Lyak提出的ESC9和ESC10Sylvain Heiniger提出的中继到RPC的 ESC11和利用条件比较局限的的ESC12,针对这条PR附带的博客文章,我尝试对这个ESC13进行分析和复现。

0x2 分析:

​ 首先,先上结论:正如标题,这不是一个可以和ESC1或者ESC8一样可以直接获取域内权限的致命漏洞,它只能算是一个域内权限提升漏洞,提升的权限取决于你错误配置指向的组的权限,且它的限制颇多。
说的详细一点的话就是,我们可以使用指向给定 AD 组的 OID 组链接的颁发策略来配置证书模板。当我们用这个模板申请证书成功之后,我们利用该证书进行身份验证就可以获取这个组的权限,哪怕我们的用户不在这个组里。

这里面涉及到三个关键:

  • 颁发策略
  • 指向AD组的OID组链接
  • 使用证书认证

我们对此进行逐步分析

证书颁发策略

证书颁发策略是指用于控制证书颁发的一组规则和条件。颁发策略定义了在何种情况下、以何种方式以及向谁颁发证书。
我们可以打开一个证书模板查看其拓展,可以看到是包括了颁发策略这一部分的,而且当前模板默认是没有值

我们可以点击编辑添加颁发策略,也可以新建我们自己的颁发策略

证书的颁发策略同样是用OID进行标志的,它存储在LDAP中的CN=OID,CN=Public Key Services,CN=Services,CN=Configuration,DC=esg-red,DC=local中,每一个CN代表一个OID对象

同样我们也可以通过powershell来查看

1
Get-ADObject -Filter * -SearchBase "CN=OID,CN=Public Key Services,CN=Services,CN=Configuration,DC=esg-red,DC=local" -Properties DisplayName,msPKI-Cert-Template-OID

注意,上面存储的OID是ADCS中所有的OID,而证书模板具有的颁发策略的OID则存储在证书模板中的msPKI-Certificate-Policy属性中

OID组链接

对应CN=OID这个容器,我们可以看到它是一个msPKI-Enterprise-Oid类,而对于这个类,它存在一个继承 的msDS-OIDToGroupLink属性

msDS-OIDToGroupLink这个属性便是ESC13的关键,它标识了与该 OID 表示的发布策略对应的组对象。换句话说,我们可以利用这个属性将我们的颁发策略和相应的AD组链接起来,如果用户利用带有相关颁发策略的证书进行身份验证,那么系统将认为该用户作为AD组的成员(用户不在该组中),并授予相应的权限。

但是并不是任何组都可以被颁发策略链接的,它需要满足以下要求

  1. 必须是AD的通用组
  2. 组内没有任何成员

当我们设置了msDS-OIDToGroupLink属性后,尝试向这个组内添加成员会报错

证书认证:

前面说到,这是利用证书颁发策略的msDS-OIDToGroupLink属性导致的权限滥用,所以我们必须要使用证书进行身份验证才行,也就是说我们的证书模板要支持证书认证。
我们可以验证一下,我们为ESCUser13用户申请具有漏洞的ESC13模板证书,我们利用Rubeus申请TGT票据,并利用krbtgt的密钥解密查看PAC部分

我们可以看到ESC13User除了默认的513User组外,没有加入任何其他组

但是在我们查看票据的PAC的时候,可以看到它拥有着ESC13Group这个组的权限

而我们利用正常账号密码申请票据,发现只有一个513User组

0x3 漏洞复现:

配置

搭建域控和ADCS的步骤这里不再赘述了
域控:DC Windows server 2019 Datacenter 10.10.10.128
ADCS:ADCS Windows server 2019 Datacenter 10.10.10.131
域名:esg-red.local
CA名:esg-red-ADCS-CA
首先我们新建一个普通用户,确保它没有加入任何其他组

1
Get-ADUser ESC13User -Properties MemberOf

然后创建一个通用组,组内没有任何用户

为了验证权限,我们为这个组设置对域内DCSync的权限

接着我们来到我们的ADCS,在终端中输入certsrv.msc打开我们的证书颁发机构,在证书模板这里右键管理打开证书模板控制台,我们可以直接复制现有的模板来创建新的漏洞模板。我们右键工作组身份验证选择复制模板,修改模板名称,在拓展这里双击颁发策略,点击添加

我们可以选择现有的颁发策略,也可以直接新建颁发策略,新建时填写名称就行了

在填完完成之后,点击拓展里的颁发策略,下面会显示已有的策略

我们需要给予用户对证书的申请权限

同时还有一个非常重要的一点,我们需要在使用者名称这里,将DNS名修改为用户主体名称(UPN),因为我们新建的用户是没有dNSHostName这个属性的,不更改的话会导致证书申请失败

我们在终端中输入adsiedit.msc打开ADSI编辑器,然后连接AD的Configuration

找到我们的OID容器,在CN=OID,CN=Public Key Services,CN=Services,CN=Configuration,DC=esg-red,DC=local下,找到我们创建的颁发策略,修改其msDS-OIDToGroupLink属性为我们创建的通用组

利用

我们找到支持ESC13的分支下载下来,进入主目录,利用find进行简单的信息收集
可以看到,成功的扫描出了ESC13这个漏洞

然后我们申请pfx证书

1
python entry.py req -u 'ESC13User@esg-red.local' -p 'Admin13' -template 'ESC13'  -target adcs.esg-red.local  -ca esg-red-ADCS-CA

我们利用申请的证书使用申请kirbi类型的票据并将其转化为Linux上使用的ccache类型

1
2
python entry.py auth -pfx esc13user.pfx -dc-ip 10.10.10.128 -kirbi
impacket-ticketConverter esc13user.kirbi esc13user.ccache

我们利用impacket分支的describeTicket.py脚本解密查看,可以看到确实是存在2616这个组的权限

1
python aaa.py esc13user.ccache --aes 3c4f06f1b46e0d5d30fe428ce08921964cae205def01fcf3b643dacf40a27983

导入票据

1
export KRB5CCNAME=esc13user.ccache

尝试DCSync攻击

1
impacket-secretsdump esg-red.local/ESC13User@DC.esg-red.local  -k -no-pass -just-dc-user 'krbtgt' -debug

0x4 总结:

感觉这个利用属于是”可遇而不可求“,感觉利用限制很多,而且获取的还不一定是高权限组的权限,不过我们可以配合其他漏洞,例如ESC5来修改PKI的ACL等。本篇文章只是暂时分析了一下成因及其简单利用,后续有其他利用姿势欢迎大佬补充,文章有什么错误也欢迎大佬斧正。