outside_default.png

目录

Kerberos基础

PAC特权属性证书

    1. PAC结构

    2. PAC凭证信息

    3. PAC签名

    4. KDC验证PAC

    5. PAC在kerberos中的优缺点

Kerberos实验

AS-REQ & AS-REP

    1. AS-REQ请求包分析

    2. AS-REP回复包分析

          (1) TGT认购权证

          (2) Logon Session Key

TGS-REQ & TGS-REP

    1. TGS-REQ请求包分析

    2. TGS-REP回复包分析

          (1) ST服务票据

          (2) Service Session Key

如何双向认证?(AP-REQ&AP-REP)

    1. AP-REQ请求包分析

    2. AP-REP回复包分析

S4u2Self&S4u2Proxy

    1. S4u2Self

    2. S4u2Proxy

Kerberos协议的安全问题

outside_default.png

      Kerberos协议是由麻省理工学院提出的一种网络身份验证协议,提供了一种在开放的非安全网络中认证识别用户身份信息的方法。它旨在通过使用密钥加密技术为客户端/服务端应用程序提供强身份验证。Kerberos是西方神话中守卫地狱之门的三头犬的名字。之所以使用这个名字是因为Kerberos需要三方的共同参与才能完成一次认证流程。目前主流使用的Kerberos版本为2005年RFC4120(https://www.rfc-editor.org/rfc/rfc4120.html)标准定义的KerberosV5版本,Windows、Linux和Mac OS均支持Kerberos协议。

一.

Kerberos基础

outside_default.png

在Kerberos协议中,主要有以下三个角色:

  • 访问服务的客户端:Kerberos客户端是代表需要访问资源的用户进行操作的应用程序,例如打开文件、查询数据库或打印文档。每个Kerberos客户端在访问资源之前都会请求身份验证。

  • 提供服务的服务端:域内提供服务的服务端,服务端都有一个独一的SPN。

  • ‍提供认证服务的KDC(Key Distribution Center,密钥分发中心):KDC密钥发行中心是一种网络服务,它向活动目录域内的用户和计算机提供会话票据和临时会话密钥,其服务帐户为krbtgt。KDC作为活动目录域服务ADDS的一部分运行在每个域控制器上。

    这里说一下krbtgt帐户,该用户是在创建活动目录时系统自动创建的一个账号,其作用是KDC密钥发行中心的服务账号,其密码是系统随机生成的,无法正常登陆主机。在后面的域学习中,会经常和krbtgt帐户打交道,关于该帐户的其他信息会在后面的文章中详细讲解。

如图所示,可以看到krbtgt帐户的信息。

765dde637e180a5c6da4fd3651a2fd22.png

 Kerberos是一种基于票据Ticket的认证方式。客户端想要访问服务端的某个服务,首先需要购买服务端认可的 ST服务票据(Service Ticket)。也就是说,客户端在访问服务之前需要先买好票,等待服务验票之后才能访问。但是这张票并不能直接购买,需要一张 TGT认购权证(Ticket Granting Ticket)。也就是说,客户端在买票之前必须先获得一张TGT认购权证。TGT认购权证ST服务票据 均是由KDC(密钥分发中心)发放;因为KDC是运行在域控制器上,所以说TGT认购权证和ST服务票据均是由域控发放。

Kerberos使用TCP/UDP 88端口进行认证,使用TCP/UDP 464端口进行密码重设。如图所示,可以看到域控制器AD01上开放的88和464端口。

193258420cfe38adf588350abacce223.png

Kerberos中一些名词的简称及含义如表所示:

简称

全拼

DC

Domain Controller,域控

krbtgt

KDC密钥发行中心服务账户

KDC

Key Distribution Center:密钥分发中心,由域控担任

AD

Active Directory:活动目录,里面包含域内用户数据库

AS

Authentication Service:认证服务

TGT

Ticket Granting Ticket:TGT认购权证,由KDC的AS认证服务发放

TGS

Ticket Granting Service:票据授予服务

ST

Service Ticket:ST服务票据,由KDC的TGS票据授予服务发放

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

    在分析AS_REQ & AS_REP 和 TGS_REQ & TGS_REP之前,我们先来看看什么是PAC。

PAC特权属性证书

outside_default.png

       PAC (Privilege Attribute Certificate,特权属性证书),其中所包含的是各种授权信息、附加凭据信息、配置文件和策略信息等。例如用户所属的用户组, 用户所具有的权限等。在最初的RFC1510中规定的标准Kerberos认证过程中并没有PAC,微软在自己的产品中所实现的Kerberos流程加入了PAC的概念,因为在域中不同权限的用户能够访问的资源是不同的,因此微软设计PAC用来辨别用户身份和权限。

       在一个正常的Kerberos认证流程中,KDC返回的TGT认购权证和ST服务票据中都是带有PAC的。这样做的好处就是在以后对资源的访问中, 服务端再接收到客户请求的时候不再需要借助KDC的帮助提供完整的授权信息来完成对用户权限的判断, 而只需要根据请求中所包含的PAC信息直接与本地资源的ACL相比较做出裁决。

1

PAC结构

PAC的顶部结构如下:

typedef unsigned long ULONG;
typedef unsigned short USHORT;
typedef unsigned long64 ULONG64;
typedef unsigned char UCHAR;


typedef struct _PACTYPE {
    ULONG cBuffers;
    ULONG Version;                         
    PAC_INFO_BUFFER Buffers[1];
} PACTYPE;

这些顶部字段的定义如下:

 · cBuffers:包含数组缓冲区中的条目数。

 · Version:版本

 · Buffers:包含一个PAC_INFO_BUFFER结构的数组。

如图所示,是WireShark抓包的PAC结构部分,可以看到cBuffers、Version和Buffers部分:

d82deac777ed5a1afa302557acb641f9.png

而PAC_INFO_BUFFER结构包含了关于PAC的每个部分的信息,这部分是最重要的,结构如下:

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

类型字段的定义如下:

 · ulType:包含此缓冲区中包含的数据的类型。它可能是以下之一:

           · Logon Info (1)

           · Client Info Type(10)

           · UPN DNS Info (12)

           · Sserver Cechksum (6)

           · Privsvr Cechksum (7)

 · cbBufferSize:缓冲大小

 · Offset:缓冲偏移量

如图所示,是WireShark抓包的PAC_INFO_BUFFER结构部分。

d68a0d62a91d7cc407844ca86d0dc53c.png

2

PAC凭证信息

    LOGON INFO类型的PAC_LOGON_INFO包含Kerberos票据客户端的凭据信息。数据本身包含在一个KERB_VALIDATION_INFO结构中,该结构是由NDR编码的。NDR编码的输出被放置在LOGON INFO类型的PAC_INFO_BUFFER结构中。如下:

typedef struct _KERB_VALIDATION_INFO {
    FILETIME Reserved0;
    FILETIME Reserved1;
    FILETIME KickOffTime;
    FILETIME Reserved2;
    FILETIME Reserved3;
    FILETIME Reserved4;
    UNICODE_STRING Reserved5;
    UNICODE_STRING Reserved6;
    UNICODE_STRING Reserved7;
    UNICODE_STRING Reserved8;
    UNICODE_STRING Reserved9;
    UNICODE_STRING Reserved10;
    USHORT Reserved11;
    USHORT Reserved12;
    ULONG UserId;
    ULONG PrimaryGroupId;
    ULONG GroupCount;
    [size_is(GroupCount)] PGROUP_MEMBERSHIP GroupIds;
    ULONG UserFlags;
    ULONG Reserved13[4];
    UNICODE_STRING Reserved14;
    UNICODE_STRING Reserved15;
    PSID LogonDomainId;
    ULONG Reserved16[2];
    ULONG Reserved17;
    ULONG Reserved18[7];
    ULONG SidCount;
    [size_is(SidCount)] PKERB_SID_AND_ATTRIBUTES ExtraSids;
    PSID ResourceGroupDomainSid;
    ULONG ResourceGroupCount;
    [size_is(ResourceGroupCount)] PGROUP_MEMBERSHIP ResourceGroupIds;
} KERB_VALIDATION_INFO;

主要还是关注以下几个字段:

 · Acct Name:该字段对应的值是用户sAMAccountName属性的值

 · Full Name:该字段对应的值是用户displayName属性的值

 · User RID:该字段对应的值是用户的RID,也就是用户SID的最后部分

 · Group RID:对于该字段,域用户的Group RID恒为513(也就是Domain Users的RID),机器用户的Group RID恒为515(也就是Domain Computers的RID),域控的Group RID恒为516(也就是Domain Controllers的RID)

 · Num RIDS:用户所属组的个数

 · GroupIDS:用户所属的所有组的RID

如图所示,是是WireShark抓包的PAC_LOGON_INFO部分。

fb8225b07b73891d6fc6a63caefcda9c.png

3

PAC签名

      PAC中包含两个数字签名:PAC_SERVER_CHECKSUM 和 PAC_PRIVSVR_CHECKSUM。PAC_SERVER_CHECKSUM是使用服务密钥进行签名,而PAC_PRIVSVR_CHECKSUM是使用KDC密钥进行签名。签名有两个原因。首先,存在带有服务密钥的签名,以验证此PAC由服务进行了签名。其次,带有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;
    UCHAR Signature[1];     
} PAC_SIGNATURE_DATA, *PPAC_SIGNATURE_DATA;

这些字段定义如下:

 · SignatureType:此字段包含用于创建签名的校验和的类型,校验和必须是一个键控的校验和。

 · Signature:此字段由一个包含校验和数据的字节数组组成。字节的长度可以由包装PAC_INFO_BUFFER结构来决定。

    如图所示,是PAC中的签名部分,可以看到PAC_SERVER_CHECKSUM和PAC_PRIVSVR_CHECKSUM。86dada464e7c4926dc42bd3b31f0b58c.png

4

KDC验证PAC

      我们注意到,PAC中是有两个签名的:PAC_SERVER_CHECKSUM 和 PAC_PRIVSVR_CHECKSUM。一个是使用服务密钥(PAC_SERVER_CHECKSUM)进行签名,另一个使用KDC密钥(PAC_PRIVSVR_CHECKSUM)进行签名。当服务端收到客户端发来的AP-REQ消息时,只能校验PAC_SERVER_CHECKSUM签名,而并不能校验PAC_PRIVSVR_CHECKSUM签名。因此,正常来说如果需要校验PAC_PRIVSVR_CHECKSUM签名的话,服务端还需要将客户端发来的ST服务票据中的PAC签名发给KDC进行校验。

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

    那么如何配置服务主机开启KDC签名校验呢,根据微软官方文档的描述,若要开启KDC校验PAC,需要有以下条件:

 · 应用程序具有SeTcbPrivilege权限。SeTcbPrivilege权限允许为用户帐户分配“作为操作系统的一部分”。本地系统、网络服务和本地服务帐户都是由windows定义的服务用户帐户。每个帐户都有一组特定的特权。

 · 应用程序是一个服务,验证KDC PAC签名的注册表项被设置为1,默认为0。修改方法如下:

    1.启动注册表编辑器regedit.exe

    2.找到以下子键:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters

    3.添加一个ValidateKdcPacSignature的键值(DWORD类型)。该值为0时,不会进行KDC PAC校验。该值为1时,会进行KDC PAC校验。因此可以将该值设置为1启用KDC PAC校验。

对于验证KDC PAC签名这个注册表键值,有以下几点注意事项:

 · 如果服务端并非一个服务程序,而是一个普通应用程序,它将不受以上注册表的影响,而总是进行KDC PAC校验。

 · 如果服务端并非一个程序,而是一个驱动,其认证过程在系统内核内完成,它将不受以上注册表的影响,而永不进行PAC校验。

 · 使用以上注册表项,需要在Windows Server 2003 SP2或更新的操作系统。

 · 在运行Windows Server 2008或更新操作系统的服务器上,该注册表项的值缺省为0(默认没有该ValidateKdcPacSignature键值),也就是不进行KDC PAC校验。

注:需要说明的是,注册在本地系统帐户下的服务无论如何配置,都不会触发KDC验证PAC签名。也就是说譬如SMB、CIFS、HOST等服务无论如何都不会触发KDC验证PAC签名。

那么为什么默认情况下,KDC都不会验证PAC的签名呢?

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

5

PAC在kerberos中的优缺点

    那么PAC的存在究竟给我们的验证过程带来了哪些优点,亦或是缺点呢?

    正如上面所提到的那样,PAC的引入其实带来了很多的优点。客户端在访问网络资源的时候服务端不再需要向KDC查询授权信息, 而是直接在本地进行PAC信息与ACL的比较。从而节约了网络资源。

如图所示, 在没有PAC的情况下,Server与KDC之间必须进行用户授权信息的查询与返回 :

fe273d32195d27c9cfcd97b2dc73ec23.png

当引入PAC之后则变成了如图所示:

bebc4c4301adfdbae5b38d102587cbf1.png

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

Kerberos实验

outside_default.png

    为了更直观的分析Kerberos协议,接下来我们用普通域帐户xie/hack使用impacket工具请求win10机器的cifs服务票据 ,然后远程SMB连接,在该过程中使用WireShark进行抓包。

实验环境如下:

用户(xie/hack):10.211.55.2

域内主机(Win10): 10.211.55.16

域控(AD01):10.211.55.4

impacket使用命令如下:

#使用hack账号密码请求win10的cifs服务的ST服务票据
python3 getST.py -dc-ip 10.211.55.4 -spn cifs/win10.xie.com xie.com/hack:P@ss1234


#导入该ST服务票据
export KRB5CCNAME=hack.ccache


#使用smb远程连接win10
python3 smbexec.py -no-pass -k win10.xie.com

如图所示,可以看到在请求了服务票据后,成功远程SMB连接win10机器。

960a7bfce1884da941d57aa5312f4cd6.png

在这个过程中,我们使用WireShark抓包,来进一步的分析Kerberos协议。如图所示,是该过程的抓包图:

b024d53e5d63241bc1952e715e0a5178.png

整个Kerberos认证流程如图所示:

f1ed42f3da965ac9ee88331fe60568ff.png

下面我们来具体分析Kerberos认证流程的每个步骤:

AS-REQ & AS-REP

outside_default.png

我们先来看看AS-REQ&AS-REP请求部分,也就是WireShark抓的第一、二个包,如图所示:

e674b97c35115f2f9459ff980b42b458.png

如图所示,是一个简易的AS-REQ&AS-REP请求过程图,便于我们直观的了解AS-REQ&AS-REP请求过程。

3797627e27198153a0f385a7310c0c7a.png

      下面让我们具体的分析下AS-REQ&AS-REP过程中的数据包细节:

      首先,我们来看看客户端是如何获得TGT认购权证的。TGT认购权证是由KDC的 AS(Authentication Service) 认证服务发放的。

1

AS-REQ请求包分析

      AS-REQ:当域内某个用户想要访问域内某个服务时,于是输入用户名和密码,本机就会向KDC的AS认证服务发送一个AS-REQ认证请求。该请求包中包含如下信息:

 · 请求的用户名(cname)。

 · 域名(realm)。

 · Authenticator:一个抽象的概念,代表一个验证。这里是用户密钥加密的时间戳。

 · 请求的服务名(sname):AS-REQ这个阶段请求的服务都是krbtgt。

 · 加密类型(etype)。

 · 以及一些其他信息:如版本号,消息类型,票据有效时间,是否包含PAC,协商选项等。

如图所示,是AS-REQ请求包的详细:

82ce56246e81332a97ff655d191eee3d.png

下面我们来看看AS-REQ请求包中每个字段的含义,如下所示:

pvno: kerberos版本号,这里为5
msg-type: 消息类型, AS_REQ 对应的是 krb-as-req(10)
padata:主要是一些认证信息,每个认证消息有type和value。
  PA-DATA PA-ENC-TIMESTAMP:这个是预认证,就是用用户Hash加密时间戳,作为value发送给KDC的AS服务。然后KDC从活动目录中查询出用户的hash,使用用户Hash进行解密,获得时间戳,如果能解密,且时间戳在一定的范围内,则证明认证通过。由于是使用用户密码Hash加密的时间戳,所以也就造成了哈希传递攻击
    padata-type: padata类型,这里是 pA-ENC-TIMESTAMP(2)
      padata-vaule: 加密后的值
        etype:  加密类型,这里是 eTYPE-AES256-CTS-HMAC-SHA1-96(18)
        cipher: 密钥
  PA-DATA PA-PAC-REQUEST:这个是启用PAC支持的扩展。这里的value对应的值为True或False,KDC根据include的值来确定返回的票据中是否需要携带PAC。
    padata-type: padata类型,这里是pA-PAC-REQUEST(128)
      padata-vaule: padata的值
        include-pac: 是否包含PAC,这里为True,说明要PAC
req-body:请求body
    padding:填充,这里为0
    kdc-options:用于与KDC协商一些选项设置
      reserved
    forwardable
     forwarded
     proxiable
     proxy
     allow-postdate
     postdated
     unused7
     renewable
     unused9
     unused10
     opt-hardware-auth
     unused12
     unused13
     constrained-delegation
     canonicalize 
     request-anonymous
     unused17
     unused18
     unused19
     unused20
     unused21
     unused22
     unused23
     unused24
     unused25
     disable-transited-check
     renewable-ok
     enc-tkt-in-skey
     unused29
     renew
     validate
    cname:请求的用户名,这个用户名存在和不存在,返回的包有差异,因此可以用于枚举域内用户名。并且当用户名存在,密码正确和错误时,返回包也不一样,因此也可以进行密码喷洒。
      name-type:名字类型,这里是KRB5-NT-PRINCIPAL(1)
      cnmae-string:名字,也就是请求的用户名
        CNameString: 请求的用户名,这里为 hack
    realm:域名,这里为XIE.COM
    sname:请求的服务,包含type和Value。在AS-REQ里面sname始终为krbtgt
      name-type:名字类型,这里是KRB5-NT-PRINCIPAL(1)
      sname-string: krbtgt用户的信息,这里有2个items
        SNameString: 这里是krbtgt用户名
        SNameString: 这里是域名XIE.COM
    till:到期时间
    rtime:也是到期时间
    nonce:随机生成的一个数
    etype:加密类型
      ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96(18)

    我们着重讲一下PA-DATA PA-ENC-TIMESTAMP字段,该字段是用于预认证。

    在AS-REQ请求包中,只有PA-DATA PA-ENC-TIMESTAMP部分是加密的,这一部分属于预认证,我们称这部分为Authenticator。

    如图所示,在impacket/krb5/kerberosv5.py中可以看到使用用户的密码Hash或用户的密码AES Key来加密时间戳。

8d53c92849b8f69af1f3857a5e66b00f.png

    对WireShark抓取的流量进行解密,如图所示,可以看到这里是使用hack用户的密钥来解密该值,如下的patimestamp和pauses是解密后的值。

2b1a31fc3c1c30057bc9db95a145c969.png

2

AS-REP回复包分析

       AS-REP:当KDC的AS认证服务接收到客户端发来的AS-REQ请求后,从活动目录数据库中取出该用户的密钥,然后用该密钥对请求包中的Authenticator预认证部分进行解密,如果解密成功,并且时间戳在有效的范围内,则证明请求者提供的用户密钥正确。

KDC的AS认证服务在成功认证客户端的身份之后,发送AS-REP响应包给客户端。AS-REP响应包中主要包括如下信息:

 · 请求的用户名(cname)。

 · 域名(crealm)。

 · TGT认购权证:包含明文的版本号,域名,请求的服务名,以及加密部分enc-part。加密部分用krbtgt密钥加密。加密部分包含Logon Session Key、用户名、域名、认证时间、认证到期时间和authorization-data。authorization-data中包含最重要的PAC特权属性证书(包含用户的RID,用户所在组的RID) 等。

 · enc_Logon Session Key:使用用户密钥加密Logon Session Key后的值,其作用是用于确保客户端和KDC下阶段之间通信安全。也就是AS-REP中最外层的enc-part。

 · 以及一些其他信息:如版本号,消息类型等。

如图所示,是AS-REP回复包的详细:

0b51fcf44e019165d3b46b3819f11a77.png

下面我们来看看AS-REP回复包中每个字段的含义,如下所示:

pvno:kerberos版本号,这里为5
msg-type:消息类型,AS_REP对应的是 krb-as-rep(11)
padata:主要是一些认证信息。一个列表,包含若干个认证消息用于认证
  PA-DATA PA-ENCTYPE-INFO2
    padata-type: padata的类型,这里是 pA-ETYPE-INFO2(19)
    padata-value: 加密后的值
      ETYPE-INFO2-ENTRY
         etype: eTYPE-AES256-CTS-HMAC-SHA1-96(18)
         salt: 盐值,这里是 XIE.COMhack
crealm: 域名,这里是XIE.COM
cname:请求的用户名
  name-type: 用户名类型,这里是 kRB5-NT-PRINCIPAL(1)
  cname-string: 1item
    CNameString: hack
ticket:TGT认购权证
  tkt-vno: TGT版本号,这里为5
  realm: 域名,这里是 XIE.COM
  sname: 服务用户名,这里是krbtgt 密码分发中心服务账号
    name-type: KRB5-NT-SRV-INST(2)
    sname-string: 2items
      SNameString: krbtgt
      SNameString: XIE.COM
  enc-part: TGT票据中的加密部分,这部门是用krbtgt的密码Hash加密的。因此如果我们拥有krbtgt的hash就可以自己制作一个ticket,这就造成了黄金票据攻击
    etype: 加密类型,这里是 eTYPE-AES256-CTS-HMAC-SHA1-96(18)
    kvno: 版本号,这里为2
    cipher:加密后的值
enc-part:Login session key,这部分是用请求的用户密码Hash加密的,作为下阶段的认证密钥。
  etype: eTYPE-AES256-CTS-HMAC-SHA1-96(18)
  kvno: 版本号,这里为3
  cipher:加密后的值

       AS-REP返回包中最重要的就是TGT认购权证和加密的Logon Session Key了。TGT认购权证中加密部分是使用krbtgt密钥加密的,而Logon Session Key是使用请求的用户密钥加密的。

    下面我们通过解密WireShark来看看TGT认购权证和Logon Session Key中到底包含哪些内容。

1

TGT认购权证

       AS-REP响应包中的ticket便是TGT认购权证了。TGT认购权证中包含一些明文显示的信息,如版本号tkt-vno、域名realm、请求的服务名sname。但是TGT认购权证中最重要的还是加密部分,加密部分是使用krbtgt帐户密钥加密的。加密部分主要包含的内容有Logon Session Key、请求的用户名cname、域名crealm、认证时间authtime、认证到期时间endtime、authorization-data等信息。

最重要的还是authorization-data部分,这部分中包含客户端的身份权限等信息,这些信息包含在PAC中。

    如图所示,是TGT认购权证:

71c539630e4b3f92ce104ca95d8a6da3.png

    我们来看看TGT认购权证中authorization-data字段下代表用户身份权限的PAC是啥样的。我们对PAC进行解密,只查看PAC的凭证信息部分PAC_LOGON_INFO。

    如图所示,最主要的还是通过User RID和Group RID来辨别用户权限的。

1f470eb9330eccf7424f289d7b60d0a6.png

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

2

Logon Session Key

      AS-REP响应包最外层的那部分便是加密的Login session Key了,其作用是用于确保客户端和KDC下阶段之间通信安全,它使用请求的用户密钥加密。

      我们对最外层的enc-part部分进行解密,如图所示,可以看到是使用hack用户的密钥对其进行解密的。

b131e50f9b8c4bb857218e5bbef7201e.png

解密结果如下:主要包含的内容是认证时间authtime、认证到期时间endtime、域名srealm、请求的服务名sname、协商标志flags等一些信息。需要说明的是,在TGT认购权证中也包含Logon Session Key。

TGS-REQ&TGS-REP

outside_default.png

    我们再来看看TGS-REQ&TGS-REP请求部分,也就是WireShark抓的第三、四个包,如图所示:

9e2c108b0e5efa63263e8c678ab38dab.png

    如图所示,是一个简易的TGS-REQ&TGS-REP请求过程图,便于我们直观的了解TGS-REQ&TGS-REP请求过程。

69c9309d700969cdd4bbc801389d51e7.png

    下面让我们具体的分析下TGS-REQ&TGS-REP过程中的数据包细节:

      客户端再收到KDC的AS-REP回复后,使用用户密钥解密enc_Logon Session Key(也就是最外层的enc-part),得到Logon Session Key,并且也拿到了TGT认购权证。之后它会在本地缓存此 TGT认购权证 和 Logon Session Key。现在客户端需要凭借这张TGT认购凭证向KDC购买相应的ST服务票据(Service Ticket)。ST服务票据是KDC的另一个服务 TGS(Ticket Granting Service)票据授予服务发放的。在这个阶段,微软引入了两个扩展子协议 S4u2self 和 S4u2Proxy(当委派的时候,才用的到,我们会在后面的4.5章中详细介绍)。

1

TGS-REQ请求包分析

     TGS-REQ:客户端拿着上一步获得的TGT认购权证发起TGS-REQ请求,向KDC购买针对指定服务的ST服务票据,该请求主要包含如下信息:

 · 域名(realm)。

 · 请求的服务名(sname)。

 · TGT认购权证。

 · Authenticator:一个抽象的概念,代表一个验证。这里使用Logon Session Key加密的时间戳。

· 加密类型(etype)。

 · 以及一些其他信息:如版本号,消息类型,协商选项,票据到期时间等。

如图所示,是TGS-REQ请求包的详细:

719f555967465915bc7ebd8aff89b7d2.png

下面我们来看看TGS-REQ请求包中每个字段的含义,如下所示:

pvno:kerberos版本号,这里为5
msg-type:消息类型,TGS_REQ对应的是 krb-tgs-req(12)
padata: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结构。如果是基于资源的约束委派,就需要指定Resource-based Constrained Delegation位。
  padata-type: padata类型,这里是 pA-TGS-REQ(1)
    padata-value: padata的值
    ap-req:这个是TGS_REQ必须携带的部分
      pvn0:5
        msg-type:krb-ap-req(14)
        padding:0
        ap-options:00000000
        reserved: False
        use-session-key: False
        mutual-required: False
        ticket AS-REP响应包中返回的TGT认购权证
            tkt-vno:5
            realm: XIE.COM
            sname
              name-type: kRB5-NT-SRV-PRINCIPAL(1)
              sname-string:2 items
                SNameString: krbtgt
                SNameString: XIE.COM
            enc-part
              etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
              kvno: 2
              cipher: 加密后的值
         authenticator: 原始Logon Session Key加密的时间戳,用于保证会话安全
           etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
            cipher: 加密后的值
req-body:请求body
    padding:这里为0
    kdc-options:用于与KDC约定一些选项设置
        reserved
    forwardable
     forwarded
     proxiable
     proxy
     allow-postdate
     postdated
     unused7
     renewable
     unused9
     unused10
     opt-hardware-auth
     unused12
     unused13
     constrained-delegation
     canonicalize 
     request-anonymous
     unused17
     unused18
     unused19
     unused20
     unused21
     unused22
     unused23
     unused24
     unused25
     disable-transited-check
     renewable-ok
     enc-tkt-in-skey
     unused29
     renew
     validate
    realm:域名,这里为XIE.COM
    sname:要请求的服务名
      name-type: KRB5-NT-SRV-INST(2)
      sname-string: 2 items
        SNameString: cifs
        SNameString: win10.xie.com
    till:到期时间,rubeus和kekeo都是20370913024805Z,这个可以作为特征来检测工具。
    nonce:随机生成的一个数。
    etype:加密类型
      ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5(23)
      ENCTYPE: eTYPE-DES3-CBC-SHA1(16)
      ENCTYPE: eTYPE-DES-CBC-MD5 (3)
      ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96(18)

    我们着重讲一下ap-req中的authenticator字段,该字段主要用于后阶段的会话安全认证。

    为了确保后阶段的会话安全,TGS-REQ中ap-req中的authenticator字段的值是用上一步AS-REP中返回的Logon Session Key加密的时间戳,如图所示:

0552d9b8839ed310e27502dbf9a92683.png

如图所示,在impacket/krb5/kerberosv5.py可以看到使用如下加密方式使用Logon Session Key加密的时间戳。

ac131fe5b79f73bdf51c2d8ff9eb4ae1.png

2

TGS-REP回复包分析

      TGS-REP:KDC的TGS服务接收到TGS-REQ请求之后。首先使用krbtgt密钥解密TGT认购权证中加密部分得到Logon Session key和PAC等信息,如果能解密成功则说明该TGT认购权证是KDC颁发的。然后验证PAC的签名,如果签名正确,则证明PAC未经过篡改。然后使用Logon Session Key解密Authenticator得到时间戳等信息,如果能够解密成功,并且票据时间在范围内,则验证了会话的安全性。在完成上述的检测后,KDC的TGS服务完成了对客户端的认证,TGS服务发送响应包给客户端。响应包中主要包括如下信息:

 · 请求的用户名(cname)

 · 域名(crealm)

 · ST服务票据:包含明文的版本号,域名,请求的服务名,以及加密部分enc-part,加密部分用服务密钥加密。加密部分包含用户名、域名、认证时间、认证到期时间、Service Session key和authorization-data。authorization-data中包含最重要的PAC特权属性证书(包含用户的RID,用户所在的组的RDI) 等。

 · enc_Service Session key:使用Logon Session key加密的Service Session key,其作用是用于确保客户端和KDC下阶段之间通信安全。

 · 以及一些其他信息:如版本号、消息类型等。

     注:这里需要说明的是,TGS-REP这步中KDC并不会验证客户端是否有权限访问服务端。因此,这一步不管用户有没有访问服务的权限,只要TGT正确,均会返回ST服务票据,这也是kerberoasting能利用的原因,任何一个域内用户,都可以请求域内任何一个服务的ST服务票据。

如图所示,是TGS-REP回复包的详细:

8ae132a58506b486fb1732ac56b270ee.png

下面我们来看看TGS-REP回复包中每个字段的含义,如下所示:

pvno:kerberos版本号,这里为5
msg-type:消息类型,TGS_REP对应的是 krb-tgs-rep(13)
crealm: 域名,这里是XIE.COM
cname:请求的用户名
  name-type: 名称类型,这里为 KRB5-NT-PRINCIPAL(1)
  cname-string: 1 item
    CNameString: hack
ticket:即ST服务票据
  tkt-vno: 服务票据版本号,这里为5
  realm: 域名,这里是XIE.COM
  sname:
    name-type: KRB5-NT-SRV-HST(3)
    sname-string: 2 items
      SNameString: cifs
      SNameString: win10.xie.com
  enc-part: 这部分是用服务的密钥加密的
    etype: 加密类型,eTYPE-AES256-CTS-HMAC-SHA1-96(18)
    kvno: 版本号,这里为3
    cipher:加密后的值
enc-part:这部分是用原始的Logon Session Key加密的。里面最重要的字段是Service session key,作为下阶段的认证密钥。
  etype: 加密类型eTYPE-AES256-CTS-HMAC-SHA1-96(18)
  cipher: 加密后的值

      TGS-REP返回包中最重要的就是ST服务票据和Service Session key了。ST服务票据中加密部分是使用服务密钥加密的,而Service Session key是使用Logon Session Key加密的。

下    面我们通过解密WireShark来看看ST服务票据和Service Session key中到底包含哪些内容。

1

ST服务票据

      TGS-REP响应包中的ticket便是ST服务票据了。ST服务票据中包含明文显示的信息,如版本号tkt-vno、域名realm、请求的服务名sname。但是ST服务票据中最重要的还是加密部分,加密部分是使用服务密钥加密的。加密部分主要包含的内容有Server Session Key、请求的用户名cname、域名crealm、认证时间authtime、认证到期时间endtime、authorization-data等信息。最重要的还是authorization-data部分,这部分中包含客户端的身份权限等信息,这些信息包含在PAC中。

    如图所示,是ST服务票据:

f4f820d6b4d6eaeb950d29d3a4983d85.png

    我们来看看ST服务票据中authorization-data字段下代表用户身份权限的PAC是啥样的。我们对PAC进行解密,只查看PAC的凭证信息部分PAC_LOGON_INFO。

    如图所示,最主要的还是通过User RID和Group RID来辨别用户权限的。可以看到,ST服务票据中的PAC和TGT认购权证中的PAC是一致的。在正常的非S4u2Self请求的TGS过程中,KDC在ST服务票据中的PAC是直接拷贝TGT票据中的PAC。

aff432f6aba3655a1bd4efae447a80c1.png

2

Service Session Key

    TGS-REP响应包最外层的那部分便是Service Session Key了,其作用是用于确保客户端和KDC下阶段之间通信安全,它使用Logon Session Key加密。

    如图所示,对其进行解密,它主要包含的内容是认证时间authtime、认证到期时间endtime、域名srealm、请求的服务名sname、协商标志flags等一些信息。需要说明的是,在ST服务票据中也包含Service Session Key。

393cef3880f3fdcb258dafd0e006cb38.png


如何双向认证?

(AP-REQ&AP-REP)

outside_default.png

      客户端在收到KDC返回的TGS-REP消息,从中取出ST服务票据后,就准备要开始申请访问服务了。

    由于我们是通过SMB协议远程连接的,因此AP-REQ&AP-REP消息是放在SMB协议中。如图所示:

03cd8f0a33fad40ce772556c60482519.png

     注:通过impacket远程连接服务默认是不需要验证提供服务的服务端的,因此这里没有AP-REP回复。

    如图所示,是一个简易的AP-REQ&AP-REP请求过程图,便于我们直观的了解AP-REQ&AP-REP请求过程。

81574e3557cba359a74ec60fa71390b5.png

1

AP-REQ请求包分析

    AP-REQ:客户端接收到KDC的TGS回复后,通过缓存的Logon Session Key解密enc_Service Session key得到Service Session Key,同时它也拿到了ST(Service Ticket)服务票据。Serivce Session Key 和 ST服务票据会被客户端缓存。

客户端访问指定服务时,将发起AP-REQ请求,该请求主要包含如下的内容:

 · ST服务票据(ticket)

 · Authenticator:一个抽象的概念,代表一个验证。这里指Serivce Session Key加密的时间戳

 · 以及一些其他信息:如版本号、消息类型,协商选项等

如图所示,是AP-REQ请求包的详细:

7c02ea6e3d74427814e825b20dfc241c.png

下面我们来看看AP-REQ请求包中每个字段的含义,如下所示:

pvno:kerberos版本号,这里为5
msg-type:消息类型, AP_REQ 对应的是 krb-ap-req(14)
Padding:填充,这里为0
ap-options: 一些协商选项
  reserved
    use-session-key
    mutual-required  该选项代表客户端是否希望验证提供服务的服务端
ticket: ST服务票据
    tkt-vno: 版本号,这里为5
    realm: XIE.COM
    sname:服务名
        name-type: KRB5-NT-SRV-INST(2)
        sname-string: 2 item2
            SNameString: cifs
            SNameString: win10.xie.com
    enc-part: ST服务票据中加密部分
        etype:加密类型,eTYPE-AES256-CTS-HMAC-SHA1-96(18)
        kvno: 版本号,这里是2
        cipher:加密后的值
authenticator: Serivce Session Key加密的时间戳
    etype:加密类型
    cipher:加密后的值

2

AP-REP回复包分析

     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请求中mutual-required协商选项是否为True,如果为True的话,说明客户端想验证服务端的身份。此时,服务端会用Service Session Key加密时间戳作为Authenticator,在AP-REP响应包中发送给客户端进行验证。

    如果mutual-required选项为False的话,服务端会根据访问令牌的权限决定是否返回相应的服务给客户端。

    注:由于impacket默认是不需要验证服务端身份的,因此如图所示是其他请求方式的AP-REP回复包截图。

22c2bf1a1a76c02c51ba30add2b9744f.png

AP-REP响应包中主要包括如下信息:

 · 版本号

 · 消息类型

 · enc-part:使用Serivce Session Key加密的时间戳。

如下是AP-REP回复包的详细:

pvno:5
msg-type:消息类型, AP_REP 对应的是 krb-ap-rep(15)
enc-part:Serivce Session Key加密的时间戳
  etype:加密类型
    cipher:加密后的值

S4u2Self&S4u2Proxy

outside_default.png

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

执行如下命令,machine$机器用户模拟administrator身份访问自身服务。

python3 getST.py -dc-ip AD01.xie.com xie.com/machine\$:root -spn cifs/ad01.xie.com -impersonate administrator

如图所示,machine$机器账号以S4u2Self协议模拟administrator身份访问自身服务

5c7abd2974923924297694ed4ca9923c.png

1

S4u2Self

    和正常的TGS-REQ请求包相比,S4u2Self协议的TGS-REQ请求包会多一个PA-DATA pA-TGS-USER,name为要模拟的用户。

并且sname也是请求的服务自身。如图所示:

7134def517aec9ffaa530a8d4579e507.png

2

S4u2Proxy

    和正常的TGS-REQ请求包相比,S4u2Proxy协议的TGS-REQ请求包会增加一个additional-tickets字段,该字段的内容就是上一步利用S4u2Self请求的ST服务票据。如图所示:

98510b3d16b1abf3583270eaeb8d6d2a.png

Kerberos协议的安全问题

outside_default.png

如图所示,是Kerberos协议各阶段容易产生的安全问题:

88902baf4401fe927482d0ea58ea2c42.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阶段,Login session key是用用户密码 Hash 加密的。对于域用户,如果设置了“Do not require Kerberos preauthentication”不需要预认证选项,此时攻击者向域控制器的 88 端口发送 AS_REQ 请求,此时域控不会做任何验证就将 TGT认购权证 和 该用户Hash加密的Login Session Key返回。因此,攻击者就可以对获取到的 用户Hash加密的Login 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的密码是随机生成的,爆破不出来。


    非常感谢您读到现在,由于作者的水平有限,编写时间仓促,文章中难免会出现一些错误或者描述不准确的地方,恳请各位师傅们批评指正。

参考:

https://www.rfc-editor.org/rfc/rfc4120.html

https://www.cnblogs.com/artech/archive/2011/01/24/kerberos.html

https://docs.microsoft.com/en-us/previous-versions/aa302203(v=msdn.10)?redirectedfrom=MSDN#signatures-pac_server_checksum-and-pac_privsvr_checksum

https://docs.microsoft.com/zh-cn/archive/blogs/apgceps/packerberos-2

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/166d8064-c863-41e1-9c23-edaaa5f36962

https://docs.microsoft.com/en-us/previous-versions/aa302203(v=msdn.10)#top-level-pac-structure

https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc772815(v=ws.10)?redirectedfrom=MSDN

https://docs.microsoft.com/zh-cn/archive/blogs/openspecification/understanding-microsoft-kerberos-pac-validation

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/3bff5864-8135-400e-bdd9-33b552051d94

相关文章:

https://www.anquanke.com/post/id/171552#h3-5

https://zhuanlan.zhihu.com/p/473625225

https://www.zhihu.com/question/22177404

- END -

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐