简介

Kerberos协议是一种网络身份认证协议,它是一个基于票据(Ticket)的系统,它允许实体在非安全网络环境下通信,向另一个实体以一种安全的方式证明自己的身份。Kerberos一词来源于古希腊神话的守护地狱的三头犬————Cerberus。
三头犬,意味着该协议认证由三方共同参与实现。三方分别是Key Distribution Center(KDC),Client和Service。

三大组成

  1. Key Distribution Center: 翻译过来就是密钥分发中心,KDC是一种网络服务,它向目录活动区域内的用户和计算机提供会话票据和临时会话密钥,其服务账户为krbtgt。KDC作为活动目录域服务的一部分运行在每个域控上。
  2. Client客户端: 每个客户端在访问资源之前都会进行请求身份验证。
  3. Service服务端: 在域内提供服务,服务端有唯一的SPN(服务主体名称)。

Kerberos基础

看一下krbtgt账户

net user krbtgt

OJ7NbN.png
改账户密码是随机生成的,无法正常登录。

客户端想要访问某个Service,需要先购买该服务认可的票据ST(Service Ticket,服务票据),等待服务验票之后才能访问。这张ST不能直接购买,需要一张TGT(Ticket Granting Ticket,认购权证),TGT和ST都是KDC负发放的,因为KDC运行在DC上,所以说TGT和ST都是DC负责发放的。
Kerberos使用TCP/UPD 88端口进行认证,使用 TCP/UDP 464端口进行密码重设。

┌──(root㉿kali2)-[~/Desktop]
└─# nmap 192.168.31.195
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-15 20:53 CST
Nmap scan report for 192.168.31.195
Host is up (0.00072s latency).
Not shown: 989 filtered tcp ports (no-response)
PORT     STATE SERVICE
53/tcp   open  domain
88/tcp   open  kerberos-sec
135/tcp  open  msrpc
139/tcp  open  netbios-ssn
389/tcp  open  ldap
445/tcp  open  microsoft-ds
464/tcp  open  kpasswd5
593/tcp  open  http-rpc-epmap
636/tcp  open  ldapssl
3268/tcp open  globalcatLDAP
3269/tcp open  globalcatLDAPssl
MAC Address: 00:0C:29:62:5C:EC (VMware)

Nmap done: 1 IP address (1 host up) scanned in 17.19 seconds

Kerberos协议有两个基础认证模块————AS_REQ & AS_REPTGS_REQ & TGS_REP以及微软扩展的两个认证模块S4UPACS4U是微软为了实现委派而扩展的模块,分为S4u2SelfS4u2Proxy。在Kerberos最初设计的流程里只说明了如何证明客户端的真是身份,并没有说明客户端是否有权限访问该服务,因为在域中不同权限的用户能够访问的资源是不同的。微软为了解决权限这个问题,引入了PAC(Privilege Attribute Certificate,特权属性证书)的概念。

PAC

在一个正常的Kerberos认证过程中,KDC返回的TGT和ST都包含PAC。这样保证在对资源的访问中,服务端接收到客户请求时候不在需要借助KDC提供完整的授权信息来对用户权限的判断,只需要根据请求种包含的PAC信息直接与本地资源的ACL相比较做出裁决。

PAC结构

PAC的顶部结构:

typedef unsigned long ULONG;
typedef unsigned short USHORT;
typedef unsigned long64 ULONG64;
typedef unsigned char UCHAR;
typedef struct _PACTYPE {
   ULONG cBuffers;
   ULONGVersion;
   PAC_INFO_BUFFER Buffers[1];
} PACTYPE;

cBuffers: 包含数组缓冲区中的条目数
Version: 版本
Buffers: 包含一个PAC_INFO_BUFFER结构的数组

PAC_INFO_BUFFER结构包含关于PAC每个部分的信息,结构如下:

typedef struct _PAC_INFO_BUFFER{
    ULONG ulType;
    ULONG cbBufferSize;
    ULONG64 Offset;
}PAC_INFO_BUFFER;

ulType: 包含此缓冲区中的数据的类型,可能是

  1. Logon Info(1)
  2. Client Info Type(10)
  3. UPN DNS Info(12)
  4. Server Checksum(6)
  5. Privsvr Checksum(7)
    cbBuuferSize: 缓冲大小
    Offset:缓冲偏移量

PAC凭证信息

Logon Info类型的PAC_LOGAN_INFO中包含Kerberos票据客户端的凭据信息。数据本身包含在一个KERB_VALIDATION_INFO结构中,该结构是由NDR编码的。NDR编码的输出被放置在Logon Info类型的PAC_INFO_BUFFER结构中。
该结构体重要的内容如下:
Acct Name: 对应的值是用户sAMAccountName属性的值
Full Name: 对应的值是用户displayName属性的值
User RID: 对应的值是用户的RID,也就是用户SID的最后部分
Group RID: 域用户的Group RID恒为513(也就是Domain Users的RID),机器用户的Group RID恒为515(也就是Domain Computers的RID),DC的Group RID恒为516(也就是Domain Controllers的RID)
Num RIDS: 用户所属组的个数
GroupIDS: 用户所属的所有组的RID

PAC签名

PAC中包含两个数字签名:PAC_SERVER_CHECKSUMPAC_PRISVR_CHECKSUM。PAC_SERVER_CHECKSUM使用服务密钥进行签名,而PAC_PRISVR_CHECKSUM使用KDC密钥进行签名。签名的原因由两个:

  1. 存在带有服务密钥的签名,以验证此PAC已由服务签名
  2. 带有KDC密钥的签名是为了防止不受信任的服务用无效的PAC为自己伪造票据
    这两个签名分别以PAC_SERVER_CHECKSUM和PAC_PRIVSVR_CHECKSUM类型的PAC_INFO_BUFFER发送。在PAC数据用于访问控制之前,必须检查PAC_SERVER_CHECKSUM签名,这将验证客户端是否知道服务的密钥。而PAC_PRIVSVR_CHECKSUM签名的验证是可选的,默认不开启。它用于验证PAC是否由KDC签发,而不是由KDC以外的具有访问服务密钥的第三方放入票据中。
    签名包含在以下结构中:
    typedef struct _PAC_SIGNATURE_DATA{
        ULONG SignatureType;
        UCHARSignature[1];
    }PAC_SIGNATURE_DATA,*PPAC_SIGNATURE_DATA;
    SignatureType: 包含用于创建签名的校验和的类型,校验和必须是一个键控的校验和。
    Signature: 由一个包含校验和数据的字节数组组成。

KDC验证PAC

当服务端收到客户端发来的AP-REQ消息时,只能校验PAC_SERVER_CHECKSUM签名,并不能校验PAC_PRIVSVR_CHECKSUM签名。
因此,如果要校验PAC_PRIVSVR_CHECKSUM签名,服务端还需要将客户端发来的ST中的PAC签名发给KDC进行校验。但是,由于大部分服务默认没有KDC验证PAC这一步,因此服务端就无须将ST中的PAC签名发给KDC校验了。
这也是白银票据攻击成功的前提,因为如果目标服务主机配置为需要校验PAC_PRIVSVR_CHECHSUM签名,服务端会将这个PAC的数字签名以KRB_VERIFY_PAC的消息通过RPC协议发送给KDC,KDC再将验证这个PAC的数字签名的结果以RPC返回码的形式发送给服务端,服务端就可以根据返回结果判断PAC的真实性和有效性。这样,就算攻击者拥有服务密钥,可以制作ST,也不能伪造KDC的PAC_PRIVSVR_CHECKSUM签名,自然就无法通过KDC签名校验。

那么,如何开启KDC签名校验?需满足以下条件:

  1. 应用程序须有SeTcbPrivilege权限。SeTcbPrivilege权限允许为用户分配“作为操作系统的一部分”。本地系统,网络服务和本地服务账户都是由Windows定义的服务用户账户。每个账户都有一组特定的特权。
  2. 应用程序是一个服务,验证KDC PAC签名的注册表项被设置为1,默认为0。修改方法如下:
    1. 启动注册表编辑器regedie.exe
    2. 找到以下子键: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters
    3. 添加一个ValidateKdcPacSignature的键值(DOWRD类型)。该值为0时,不会进行KDC PAC校验;该值为1时,会进行KDC PAC校验。因此可以将该设置为1,启用KDC PAC校验。

OJZGwb.png
我的电脑默认没开启。
对于验证KDC PAC签名的注册表键值,有以下几点注意事项:

  1. 如果服务端并非一个服务程序,而是一个普通应用程序,它将不受上面注册表的影响,而总会进行KDC PAC的校验。
  2. 如果服务端并非一个程序,而是一个驱动,其认证过程在系统内核内完成,它将不受以上注册表的影响,而永不进行KDC PAC的校验。
  3. 使用以上注册表项,需要在Windows Server 2003 SP2或更新的操作系统中进行。
  4. 运行在Windows Server 2008或更新操作系统的服务器上,该注册表项的值默认为0(默认没有ValidateKdcPacSignature键值),也就是不进行KDC PAC校验。例如我的计算机。
  5. 注册在本地系统账户下的服务,无论如何配置都不会触发KDC PAC签名校验,如SMB,SCIFS,HOST等服务无论如何都不会触发KDC PAC的校验。

为何默认不进行KDC PAC的验证?
因为如何执行KDC验证PAC,意味着有响应时间和带宽使用方面的成本。它需要占用带宽在应用服务器和KDC之间传输请求和响应,这可能导致大容量应用程序服务器中出现一些性能问题。在这样的环境中,用户身份验证可能导致额外的网络延迟和大量的流量。

PAC在Kerberos中的优缺点

  1. 无PAC情况
    OJZYfa.png
  2. 有PAC情况
    OJZl5S.png

But,PAC的引入并不是完全有利的,PAC在用户认证的时候会导致认证耗时过长。Windows Kerberos客户端会通过RPC调用KDC上的函数来验证PAC信息,这时候用户会观察到在服务断与KDC之间的RPC包流量的增加。而另一方面,由于PAC是微软特有的一个特性,所以启用了PAC的域中不支持装有其他操作系统的服务器,制约了域配置的灵活性。在2014年,PAC的安全性还导致产生了一个域内及其严重的提取漏洞MS14-068。

Kerberos完整认证过程

OJgH5p.png

AS-REQ&AS-REP

OJgLKU.png
Server的TGT是由KDC的AS(Authentication Server,认证服务)发放的/

  1. AS-REQ分析
    当域内某个用户想要访问域内某个服务时,输入用户名和密码,本机就会向KDC的AS发送一个AS-REQ的请求包。AS-REQ请求包有如下字段:
    PA-DATA pA-ENC-TIMESTAMP:预认证,就是用用户Hash加密时间戳作为value发送给KDC的AS。然后KDC从活动目录中查询出用户的Hash,使用用户Hash进行解密,获得时间戳。如果能解密,且时间戳在一定范围内,则证明认证通过。由于是使用用户密码Hash加密时间的时间戳,因此造成了PTH攻击。
    PA-DATA pA-PAC-REQUEST: 启用PAC支持的扩展,这里value对应的值为True或Fasse,KDC根据include的值来确定返回的票据中是否需要携带PAC。
    include-pac: 是否包含PAC,True表示包含
    kdc-options: 用于与KDC协商一些选项设置
    cname: 请求的用户名,这个用户木存在与否,返回的包是有差异的,因此可以用于枚举域内用户名。当用户名存在时,密码正确与否是否会影响返回包,因此也可以进行密码喷洒
    realm: 域名
    sname: 请求的服务,包含type和value。在AS-REQ中sname始终未krbtgt。

  2. AS-REP
    当KDC的AS接收到客户端发来的AS-REQ后,AS会从活动目录数据库中取出该用户的密钥,然后用该密钥对请求包中的预认证部分进行解密。如果解密成功,并且时间戳在有效范围内,则证明请求者提供的用户密钥正确。KDC的AS在成功认证客户端的身份之后,发送AS-REP包给客户端。
    AS-REP包有如下主要字段:
    ticket: 认购权证票据
    enc-part(ticket中的): TGT中的加密部分,这部分是用krbtgt的密码Hash加密的。因此如果拥有krbtgt的Hash就可以自己制作一个ticket,这就造成了黄金票据传递攻击
    enc-part(最外层的): Logon Session Key,这部分是用请求的用户密码Hash加密的,作为下一阶段的认证密钥。

AS-REP包中最重要的就是TGT和加密的Logon Session Key。TGT中加密部分是使用krbrgt密钥加密的,而Logon Session Key是使用请求的用户密钥加密的。

(1)TGT
AS-REP包中的ticket便是TGT。TGT中包含一些明文信息,如版本号tkt-vno,域名realm,请求的服务名sname,最重要的是加密部分。加密部分是使用krbrgt账户密钥加密,主要包含Logon Session Key,请求的用户木cname,域名crealm,认证时间authtime,认证到期时间endtime,authorization-data等信息。其中authorization-dataq部分包含客户端的身份权限等信息,这些信息包含在PAC中。

KDC生成PAC的过程: KDC在收到客户端发来的AS-REQ后,从请求中取出cname字段,然后查询活动目录数据库,找到sAMAccountName属性为cname字段的值用户,用该用户的身份生成一个对应的PAC。

(2)Logon Session Key
AS-REP包最外层的部分就是加密的Logon Session Key,用于确保客户端和KDC下一阶段的通信安全,它使用请求的用户密钥加密。

TGS-REQ & TGS-REP

OJgH5p.png
OJPSd1.png
客户端收到KDC的AS-REP后,使用用户密钥解密enc_Logon Session Key,得到Logon Session Key,并且也获得了TGT。之后它会在本地缓存此Logon Session Key。客户端需要凭借这张TGT向KDC购买响应的ST。ST是KDC的另一个服务TGS(Ticket Granting Service)授予的。在这个阶段,微软引入了两个扩展自协议S4u2SelfS4u2Proxy

  1. TGS-REQ分析
    客户端用上一步获得的TGT发起TGS-ERQ向KDC购买ST。TGS-REQ包主要有如下字段:
    padata: 包含ap_req,这个是TGS_REQ必须携带的部分,这部分包含AS_REP中获取到的TGT票据和使用原始的Logon Session Key加密的时间戳。可能会有PA_FOR_USER,类型是S4u2Self,是唯一的标识符,指示用户的身份,由用户名和域名组成。S4u2Proxy必须扩展PA_FOR_USER结构,用于指定服务代表某个用户去请求针对服务自身的Kerberos服务票据。还可能会有PA_PAC_OPTIONS,类型是PA_PAC_OPTIONS。S4u2Proxy必须扩展PA-PAC-OPTIONS结构。如果是基于资源的约束性委派,就需要只当Resourse-based Constrained Delegation位。
    ap-req: 这个是TGS_REQ必须携带的部分。
    ticket: AS-REP回复包中返回的TGT
    authenticator: 原始Logon Session Key加密的时间戳,用于保证会话安全。
  2. TGS-REP分析
    KDC的TGS服务接收到TGS-REQ之后会进行如下操作。首先,使用krbrgt密钥解密TGT中的加密部分,得到Logon Session Key和PAC等信息,解密成功则说明该TGT是KDC颁发的;然后,验证PAC的签名,签名正确证明PAC未经过篡改;最后,使用Logon Session Key解密authenticator得到的时间戳等信息,如果能够解密成功,并且票据时间在有效范围内,则验证了会话的安全性。
    在完成上述检测后,KDC的TGS就完成了对客户端的认证,TGS发送回复包给客户端。(TGS-REP中的KDC并不会验证客户端是否有权限访问服务端,因此,不管用户有没有访问服务的权限,只要TGT正确,均会返回ST)
    TGS-REP包的主要字段:
    ticker: ST
    enc-part(ticket内层): 这部分是用服务的密钥加密的
    enc-part(外层) 这部分用原始的Logon Session Key加密,里面最重要的字段是Service Session Key,作为下一阶段的认证密钥

AP-REP&AP-REP双向认证

OJgH5p.png
OJPcOI.png
客户端收到KDC返回的TGS-REP消息后,从中取出ST,准备开始申请访问服务。

  1. AP-REQ包分析
    客户端收到KDC的TGS回复后,通过缓存的Logon Session Key解密enc_Service Session Key得到Service Session Key,同时也拿到了STService Session KeyST会被客户端缓存。客户端访问指定服务时,将发起AP-REQ。该包的主要字段:
    ticket: 票据
    authenticator: Service Session Key加密的时间戳
  2. AP-REP包分析
    这一步是可选的,当客户端希望验证提供服务的服务端时(也就是AP-REQ请求中mutual-required选项为True),服务端返回AP-REP消息。服务端收到客户端发来的AP-REQ消息后,通过服务密钥解密ST得到Service Session Key和PAC等消息,然乎用Service Session Key解密Authenticator得到时间戳。如果解密成功且时间戳在有效范围内,则验证了了客户端的身份。验证客户端身份后,服务端从ST中取出PAC代表用户身份权限信息的数据,然后与请求的服务ACL做对比,生成响应的访问令牌。同时,服务端会检查AP-REQ请求中matual-required选项是否为True,如果是,则说明客户端向验证服务端的身份。此时,服务端会用Service Session Key加密时间戳作为Authenticator,在AP-REP包中发送给客户端进行验证。如果mutual-required选项为False,服务端会根据访问令牌的权限决定是否返回响应的服务给客户端。

S4u2Self&S4u2Proxy协议

为了在Kerberos协议层面对约束性委派进行支持,微软对Kerberos协议扩展了两个自协议:S4u2Self(Service for User to Self)和S4u2Proxy(Service for User to Proxy)。S4u2Self可以代表任意用户请求针对自身的服务票据;S4u2Self可以用上一步获得的ST以用户的名义请求针对其他指定服务的ST。

  1. S4u2Self
    和正常的TGS-REQ包相比,S4u2Self协议的TGS-REQ包会多一个PA-DATA pA-FOR-USER,name为要模拟的用户,并且sname也是请求的服务自身。
  2. S4u2Proxy
    和正常的TGS-REQ包相比,S4u2Proxy协议的TGS-REQ包会增加一个additional-tickets字段,该字段的内容就是上一步利用S4u2Self请求的ST。

Kerberos协议的安全问题

OJPdND.png
在AS-REQ阶段,使用的是用户密码Hash或AES Key加密的时间戳。当只获得了用户密码Hash时,发起AS-REQ会造成PTH攻击;当只获得用户密码的AES Key时,发起AS-REQ会造成PTK攻击
AS-REQ包中cname代表用户名,这个值存在和不存在,返回的包不一样,所以可以用于枚举域内用户名,这种攻击方式被称为域内用户枚举攻击(当未获取到有效域用户权限时,可以使用这个方法枚举域内用户)。当用户木存在,密码正确和错误时,返回的包也不一样,所以可以进行用户木密码爆破。
在实战中,常常使用密码喷洒(Password Spraying)攻击方式。对密码进行喷洒式的攻击,其属于自动化密码猜测的一种。这种针对所有用户的自动密码喷洒通常是为了避免账户被锁定,因为针对同一个用户的连续密码猜测会导致账户被锁定,所以只有对所有用户同时执行特定的密码登录,才能增加破解的概率,并且避免账户被锁定。普通的爆破就是用户名固定爆破密码,但是密码喷洒是用固定的密码去爆破所有的用户名。

在AS-REP阶段,由于返回的TGT是由krbtgt用户的密码Hash加密的,因此如果有krbtgt的密码Hash就可以自己制作一个TGT,这个票据也被称为黄金票据,这种攻击方式被称为黄金票据传递攻击。同样,在TGS-REP阶段,TGS-REP中的ST是使用服务的Hash进行加密的,如果我们拥有服务的Hash就可以签发任意用户的ST,这个票据也被称为白银票据,这种攻击方式被称为白银票据传递攻击。相较于黄金票据传递攻击,白银票据传递攻击使用的是要访问服务的Hash,而不是krbtgt的Hash。

在AS-REP阶段,Logon Session Key是用用户密码的Hash加密的。对于域用户,如果设置了Do not reqire Kerberos preauthentication(不需要预认证)选项,攻击者会向域控的88端口发送AS_REQ,此时域控不会做任何验证就将TGT和该用户的Hash加密的Logon Session Key返回。这样,攻击者就可以对获取到的用户Hash加密的Logon Session Key进行破解,如果破解成功,就能拿到该用户的密码明文,这种攻击方式被称为AS-REP Roasting攻击

在TGS-REP阶段,由于ST是用服务Hash加密的,因此,如果我们能获取到ST,就可以对该ST进行破解,得到服务的Hash,造成Kerberoasting攻击。这种攻击方式存在的另一个原因是用户向KDC发起TGS-REQ请求时,不管用户对服务有没有访问权限,只要TGT正确,KDC都会返回ST。其实AS_REQ中的服务就是krbtgt,也就是说这种攻击方式同样可以用于爆破AS_REP中的TGT,但之所以没见到这种攻击方式是因为krbtgt的密码是随机生成的,爆破不出来。