目录
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协议的安全问题
Kerberos协议是由麻省理工学院提出的一种网络身份验证协议,提供了一种在开放的非安全网络中认证识别用户身份信息的方法。它旨在通过使用密钥加密技术为客户端/服务端应用程序提供强身份验证。Kerberos是西方神话中守卫地狱之门的三头犬的名字。之所以使用这个名字是因为Kerberos需要三方的共同参与才能完成一次认证流程。目前主流使用的Kerberos版本为2005年RFC4120(https://www.rfc-editor.org/rfc/rfc4120.html)标准定义的KerberosV5版本,Windows、Linux和Mac OS均支持Kerberos协议。
一.
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票据授予服务发放 |
二
PAC特权属性证书
1
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结构的数组。
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:缓冲偏移量
2
PAC凭证信息
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;
3
PAC签名
typedef struct _PAC_SIGNATURE_DATA {
ULONG SignatureType;
UCHAR Signature[1];
} PAC_SIGNATURE_DATA, *PPAC_SIGNATURE_DATA;
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之间必须进行用户授权信息的查询与返回 :
当引入PAC之后则变成了如图所示:
但是,PAC的引入并不是百利而无一害的,PAC在用户的认证阶段引入会导致认证耗时过长。Windows Kerberos客户端会通过RPC调用KDC上的函数来验证PAC信息,这时候用户会观察到在服务器端与KDC之间的RPC包流量的增加。而另一方面, 由于PAC是微软特有的一个特性,所以启用了PAC的域中将不支持装有其他操作系统的服务器, 制约了域配置的灵活性。并且在2014年,由于PAC的安全性导致产生了一个域内极其严重的提权漏洞MS14-068(在后面的文章中我们会介绍这个漏洞)。
三
Kerberos实验
为了更直观的分析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:[email protected]
#导入该ST服务票据
export KRB5CCNAME=hack.ccache
#使用smb远程连接win10
python3 smbexec.py -no-pass -k win10.xie.com
如图所示,可以看到在请求了服务票据后,成功远程SMB连接win10机器。
在这个过程中,我们使用WireShark抓包,来进一步的分析Kerberos协议。如图所示,是该过程的抓包图:
整个Kerberos认证流程如图所示:
下面我们来具体分析Kerberos认证流程的每个步骤:
四
AS-REQ & AS-REP
我们先来看看AS-REQ&AS-REP请求部分,也就是WireShark抓的第一、二个包,如图所示:
如图所示,是一个简易的AS-REQ&AS-REP请求过程图,便于我们直观的了解AS-REQ&AS-REP请求过程。
下面让我们具体的分析下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请求包的详细:
下面我们来看看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)
2
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回复包的详细:
下面我们来看看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认购权证:
我们来看看TGT认购权证中authorization-data字段下代表用户身份权限的PAC是啥样的。我们对PAC进行解密,只查看PAC的凭证信息部分PAC_LOGON_INFO。
如图所示,最主要的还是通过User RID和Group RID来辨别用户权限的。
KDC生成PAC的过程如下:KDC在收到客户端发来的AS-REQ请求后,从请求中取出cname字段,然后查询活动目录数据库,找到sAMAccountName属性为cname字段的值的用户,用该用户的身份生成一个对应的PAC。
2
Logon Session Key
AS-REP响应包最外层的那部分便是加密的Login session Key了,其作用是用于确保客户端和KDC下阶段之间通信安全,它使用请求的用户密钥加密。
我们对最外层的enc-part部分进行解密,如图所示,可以看到是使用hack用户的密钥对其进行解密的。
解密结果如下:主要包含的内容是认证时间authtime、认证到期时间endtime、域名srealm、请求的服务名sname、协商标志flags等一些信息。需要说明的是,在TGT认购权证中也包含Logon Session Key。
五
TGS-REQ&TGS-REP
我们再来看看TGS-REQ&TGS-REP请求部分,也就是WireShark抓的第三、四个包,如图所示:
如图所示,是一个简易的TGS-REQ&TGS-REP请求过程图,便于我们直观的了解TGS-REQ&TGS-REP请求过程。
下面让我们具体的分析下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请求包的详细:
下面我们来看看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加密的时间戳,如图所示:
如图所示,在impacket/krb5/kerberosv5.py可以看到使用如下加密方式使用Logon Session Key加密的时间戳。
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回复包的详细:
下面我们来看看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服务票据:
我们来看看ST服务票据中authorization-data字段下代表用户身份权限的PAC是啥样的。我们对PAC进行解密,只查看PAC的凭证信息部分PAC_LOGON_INFO。
如图所示,最主要的还是通过User RID和Group RID来辨别用户权限的。可以看到,ST服务票据中的PAC和TGT认购权证中的PAC是一致的。在正常的非S4u2Self请求的TGS过程中,KDC在ST服务票据中的PAC是直接拷贝TGT票据中的PAC。
2
Service Session Key
TGS-REP响应包最外层的那部分便是Service Session Key了,其作用是用于确保客户端和KDC下阶段之间通信安全,它使用Logon Session Key加密。
如图所示,对其进行解密,它主要包含的内容是认证时间authtime、认证到期时间endtime、域名srealm、请求的服务名sname、协商标志flags等一些信息。需要说明的是,在ST服务票据中也包含Service Session Key。
六
如何双向认证?
(AP-REQ&AP-REP)
客户端在收到KDC返回的TGS-REP消息,从中取出ST服务票据后,就准备要开始申请访问服务了。
由于我们是通过SMB协议远程连接的,因此AP-REQ&AP-REP消息是放在SMB协议中。如图所示:
注:通过impacket远程连接服务默认是不需要验证提供服务的服务端的,因此这里没有AP-REP回复。
如图所示,是一个简易的AP-REQ&AP-REP请求过程图,便于我们直观的了解AP-REQ&AP-REP请求过程。
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请求包的详细:
下面我们来看看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回复包截图。
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
为了在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身份访问自身服务。
1
S4u2Self
和正常的TGS-REQ请求包相比,S4u2Self协议的TGS-REQ请求包会多一个PA-DATA pA-TGS-USER,name为要模拟的用户。
并且sname也是请求的服务自身。如图所示:
2
S4u2Proxy
和正常的TGS-REQ请求包相比,S4u2Proxy协议的TGS-REQ请求包会增加一个additional-tickets字段,该字段的内容就是上一步利用S4u2Self请求的ST服务票据。如图所示:
八
Kerberos协议的安全问题
如图所示,是Kerberos协议各阶段容易产生的安全问题:
在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的密码是随机生成的,爆破不出来。
非常感谢您读到现在,由于作者的水平有限,编写时间仓促,文章中难免会出现一些错误或者描述不准确的地方,恳请各位师傅们批评指正。