Kerberos身份验证流程及Kerberos流量解密
前言:作为kerberos的认证笔记
参考文章:https://daiker.gitbook.io/windows-protocol/kerberos/1
参考文章:https://medium.com/tenable-techblog/decrypt-encrypted-stub-data-in-wireshark-deb132c076e7
参考文章:https://github.com/dirkjanm/forest-trust-tools/blob/master/keytab.py
介绍
Kerberos 是一种由 MIT(麻省理工大学)提出的一种网络身份验证协议。它旨在通过使用密钥加密技术为客户端/服务器应用程序提供强身份验证。
在 Kerberos 认证中,最主要的问题是如何证明「你是你」的问题,如当一个 Client 去访问 Server 服务器上的某服务时,Server 如何判断 Client 是否有权限来访问自己主机上的服务,同时保证在这个过程中的通讯内容即使被拦截或篡改也不影响通讯的安全性,这正是 Kerberos 解决的问题。在域渗透过程中 Kerberos 协议的攻防也是很重要的存在。
Kerberos 主要是用在域环境下的身份认证协议。
Kerberos协议
在 Kerberos 协议中主要是有三个角色的存在:
1、访问服务的 Client;
2、提供服务的 Server;
3、KDC(Key Distribution Center)密钥分发中心(其中包含了The Authentication Server 和 The Ticket Granting Server)
注意:
1、KDC 服务默认会安装在一个域的域控中
2、从物理层面看,AD与KDC均为域控制器(Domain Controller)
3、AD其实是一个类似于本机SAM的一个数据库,全称叫account database,存储所有client的白名单,只有存在于白名单的client才能顺利申请到TGT
4、KDC 服务框架中包含一个 KRBTGT 账户,它是在创建域时系统自动创建的一个账号,你可以暂时理解为他就是一个无法登陆的账号,在发放票据时会使用到它的密码 HASH 值。
上文提到的TGT,KDC,client,server又是什么东西呢,下文来介绍下:
Kerberos粗略的验证流程:
先来举个例子:如果把 Kerberos 中的票据类比为一张火车票,那么 Client 端就是乘客,Server 端就是火车,而 KDC 就是就是车站的认证系统。如果Client端的票据是合法的(由你本人身份证购买并由你本人持有)同时有访问 Server 端服务的权限(车票对应车次正确)那么你才能上车。当然和火车票不一样的是 Kerberos 中有存在两张票,而火车票从头到尾只有一张。
在KDC中又分为两个部分:Authentication Service和Ticket Granting Service
Authentication Service
Authentication Service的作用就是验证 Client 端的身份(确定你是身份证上的本人),验证通过就会给一张 TGT(Ticket Granting Ticket)票给 Client。
Ticket Granting Service
TGS 的作用是通过 AS 发送给 Client 的票(TGT)换取访问 Server 端的票(上车的票 ST)。ST(ServiceTicket)也被称之为 TGS Ticket,为了和 TGS 区分,在这里就用 ST 来说明,所以TGS Ticket和ST的意思是一样的。
这就说明了为什么在Kerberos中存有两种票,其实就是更加细分了其中的验证,简单的描述就是首先你拿身份证验证头像是不是一样,是的话就返回一张TGT,然后在通过验证车票获得上车的资格,这里就有对TGT的验证,通过的话再返回一张ST/TGS Ticket的票,如果都可以那么的话,那么才算验证通过。
Kerberos 详解认证流程
当 Client 想要访问 Server 上的某个服务时,需要先向 AS 证明自己的身份,然后通过 AS 发放的 TGT 向 Server 发起认证请求,这个过程分为三块:
The Authentication Service Exchange:Client 与 AS 的交互,
The Ticket-Granting Service (TGS) Exchange:Client 与 TGS 的交互,
The Client/Server Authentication Exchange:Client 与 Server 的交互。
The Authentication Service Exchange
KRB_AS_REQ(请求):
Client->AS:Client 先向 KDC 的 AS 发送 pA-ENC-TIMESTAMP
(内容为Client hash加密的时间戳 ps:这个时间戳我不知道是不是随机生成的)
除了pA-ENC-TIMESTAMP(内容为Client hash加密的时间戳),还有一些其他的信息,如下图所示
KRB_AS_REP(应答):
AS->Client:AS根据用户名在AD中寻找是否在AD数据库中,然后根据Client的用户名提取到对应的Hash,接着pA-ENC-TIMESTAMP用对应Client用户名的Hash进行解密,如果结果正确则会返回如下:
1、返回当前KDC中krbtgt hash加密的TGT票据(TGT包含PAC,PAC包含Client的sid,Client所在的组),在通信数据包中显示的就是ticket
字段
2、Authentication Service会生成一个随机数Session key(这个非常重要,作为kerberos中下一轮的认证密钥),返回给Client由Client的HASH加密的enc-part
字段
需要注意:这里的PAC我不知道是不是一定需要,因为我发包测试的时候,在KRB_AS_REQ请求的时候也可以指定不需要PAC验证
上面说的ticket
和enc-part
是什么?,如下图所示
AS验证的总结:在 KDC(AD) 中存储了域中所有用户的密码 HASH,当 AS 接收到 Client 的请求之后会根据 KDC 中存储的密码来解密,解密成功并且验证信息,如下验证成功后返回给Client如下两个东西:
1、随机生成的Session key,然后用Client用户 HASH 加密的 enc-part
2、TGT(由 KRBTGT HASH 加密的 session key 和 TimeStamp 等信息),也就是ticket
问题:为什么一般工具导出的TGT和TGS票据为.ccache和.kirbi?
mimikatz,kekeo,rubeus生成的凭据是以.kirbi后缀的。
impacket 生成的凭据的后缀是.ccache。
两种票据主要包含的都是enc-part
和ticket
,通过相关的工具可以使得它们之间相互转化。
就比如类似这种名称ske@hengge.com_637751390371057049_tgt.kirbi
这里就继续来解释,我们得了解相关的结构体,这里的语法是通过ASN语法来表示的,首先是KRB-CRED,这个结构体就是所谓的.kirbi
其中包含了重点的两个部分,一个是tickets
,一个是enc-part
,到这里大家可能就发现了,其实这个kirbr结构体最重要的两个部分也就是我们上面所说的两个部分ticket
和enc-part
这里继续了解下所谓的ticket
和enc-part
结构体的部分。
其中ticket
实际上就是tickets[2] SEQUENCE OF Ticket
KRB-CRED::= [APPLICATION 22] SEQUENCE {
pvno[0] INTEGER(5),
msg-type[1] INTEGER(22),
tickets[2] SEQUENCE OF Ticket, // 这个就是所说的 ticket 也就是tgt 或者 tgs
enc-part[3] EncryptedData -- EncKrbCredPart // 这个就是所说的 enc-part,用作认证密钥
}
通过daiker提供的工具抓包就是如下这个ticket
部分
再来看EncKrbCredPart,也就是所谓的enc-part
,其中ticket-info部分的主要内容是enc-part
,来自于用户HASH解密enc_part的部分,这里面最重要的就是拥有一个随机生成Session key,这个是用来作为下阶段的认证密钥。
EncKrbCredPart ::= [APPLICATION 29] SEQUENCE {
ticket-info [0] SEQUENCE OF KrbCredInfo, //这里就只用到这个
nonce [1] UInt32 OPTIONAL,
timestamp [2] KerberosTime OPTIONAL,
usec [3] Microseconds OPTIONAL,
s-address [4] HostAddress OPTIONAL,
r-address [5] HostAddress OPTIONAL
}
图中如下所示,紫色框中就是所谓的ticket-info
,其实就一条,下面那些是daiker工具会自动用Client的Hash帮你解密来进行展示的
最后大家肯定对这个Session key还是有点疑问,我这里把这个值拿出来给大家看,这个Session key,我们之前说过是一个随机值,主要是作用是作为下一轮认证密钥存在的
daiker提供的工具可以对enc-part
进行解密(工具自动用Client的Hash帮你解密来进行展示的),随机生成的Session key就在这里面,如下图所示
The Ticket-Granting Service (TGS) Exchange
然后继续来讲相关的TGS的认证过程
KRB_TGS_REQ(请求):
Client 接收到了加密后的ticket
(TGT) 和 enc-part
之后,先对enc-part
用自身密码HASH解密得到Session key,也就是上文中说的 随机生成的Session key。
TGT是由KDC中krbtgt的Hash加密,所以Client 无法解密。
这时 Client 继续再用Session key加密的TimeStamp(ps:这个时间戳我不知道是不是随机生成的)authenticator
,然后再和ticket
(TGT) 一起发送给 KDC 中的 TGS(TicketGranting Server)票据授权服务器换取能够访问 Server 的票据。
"Client 再用Session key加密的TimeStamp的部分",其实就是如下,实际上加密完的字段值应该叫做authenticator
然后这里面的ticket
其实还是我们的TGT票据,这里的enc-part
不是上面说的enc-part
,这里的enc-part
(TGT)
KRB_TGS_REP(应答):
TGS 收到 Client 发送过来的ticket
(TGT) 和 Session key 加密TimeStamp的 authenticator
之后,首先会检查自身是否存在 Client 所请求的服务。如果服务存在,则用 krbtgt的HASH来解密ticket
(TGT)。
一般情况下 TGS 会检查 TGT 中的时间戳查看 TGT 是否过期,且原始地址是否和 TGT 中保存的地址相同。
验证成功之后将返回Client两个东西,一个是用 Session key 加密的enc-part
,然后另一个是 Client要访问的Server的密码 HASH 加密的 TGS票据(要访问服务端的Hash)生成就是ST(TGS)票据,那么此时的ticket
就是TGS了
如下图所示,这个过程其实跟我们请求TGT是一样的,我就不讲了,你可以看到一个ticket
(TGS)和一个enc-part
enc-part
这个部分同样是可以解密的,原因就是这里enc-part
加密用的密钥,实际上就是上一轮AS_REP里面返回的Session key,从开始到现在这里的Session key一直都是一样的,作为下一轮通信的认证密钥。
其实我这里有点是不懂的,我看了daiker的文章,他没有说这个enc-part
是用什么解密的,如下图所示,我也不太懂,所以这个点只能放在这里了
The Client/Server Authentication Exchange
KRB_AP_REQ(请求):
到此,客户端就可以用 ST 来向服务端发出申请了。客户端向服务器发送类型为 KRB_AP_REQ 类型的消息
发送的信息有如下两个,其实就跟上面的流程一样了
1、一个新生成的 Authenticator
,包括 客户ID 和 时间戳,由Session key进行加密
2、TGS(ST)
KRB_AP_REP(应答):
服务端接收后,用自己的 Hash 解密 ST,获取会话密钥,解密获得 Authenticator,和ST中的信息对比,来确定用户的身份。确定身份后,就拿着PAC去KDC那边问Client有没有访问权限,域控解密PAC。获取Client的sid,以及所在的组,再根据该服务的ACL,判断Client是否有访问服务的权限,到此完成整个认证流程(大多数服务并没有验证PAC这一步)。
上文文字描述的也就是最开头的图片,这里再放上去,是不是会发现这张图理解了???
解密kerberos流量
参考文章:https://medium.com/tenable-techblog/decrypt-encrypted-stub-data-in-wireshark-deb132c076e7
参考文章:https://github.com/dirkjanm/forest-trust-tools/blob/master/keytab.py
这边将域控机器上面的相关的krbtgt的ntlm以及aes256_hmac和aes128_hmac
mimikatz # lsadump::dcsync /user:hengge\krbtgt
然后将上面获取到的ntlm以及aes256_hmac和aes128_hmac替换到下面的keytab.py文件中
通过python生成对应的keytab文件,如下图所示
python3 newkeytab.py krbtgt.keytab
将keytab文件导入到wireshark中,如下图所示
可以看到Kerberos的流量已经正确进行解密,如下图所示
注意:这里的ntlm以及aes256_hmac和aes128_hmac可以放置多个,wireshark中导入后会自动遍历进行解密直到成功