深入理解 Kerberos 协议 (上)
Kerberos 过程详解
Kerberos 协议通过密钥系统为客户端与服务提供认证服务,为了解决当客户端去访问一个服务器的某服务时,服务器如何判断该对象是否有相关权限来访问自己的服务
客户端用户 A 登陆域成员机,然后访问某个服务,这个过程就涉及到了 kerberos 协议

简单来说,kerberos 协议的整个过程如下:

-
Client 向 KDC 发起 AS_REQ,请求的凭据是 Client hash 加密的时间戳
-
KDC 使用 Client hash 进行解密,如果结果正确就返回用 krbtgt hash 加密的 TGT 票据,TGT 里面包含 PAC,PAC 包含 Client 的 sid、Client 所在的组
-
Client 凭借 TGT 票据向 KDC 发起针对特定服务的 TGS_REQ 请求
-
KDC 使用 krbtgt hash 进行解密,如果结果正确,就返回用服务 hash 加密的 TGS 票据(这一步不管用户有没有访问服务的权限,只要TGT正确,就返回TGS票据)
-
Client 拿着 TGS 票据去请求服务
-
服务使用自己的 hash 解密 TGS 票据。如果解密正确,就拿着 PAC 去 KDC 那边问 Client 有没有访问权限。域控解密PAC,获取 Client 的 sid、以及所在的组,再根据该服务的 ACL,判断 Client 是否有访问服务的权限
下面详解上面的 登陆、认证、授权、请求服务 这四个步骤
用户登陆
用户A在登陆阶段,会输入 [用户名][密码] ,并且用户 A 输入的 [密码] 会通过一个单向的 Hash 函数 生成一个 [Client密钥],更准确的说,这个 [Client密钥] 也被称为 [Client Hash]
请求身份认证
1) 客户端向 AS 发送认证请求
客户端为执行登陆操作的用户A向 AS 发送 AS-REQ 请求,请求中带有 [Client密钥] 加密的 时间戳 、 [用户名] 等信息
2) AS 确认 Client 端登陆者用户身份
AS 收到用户A的认证请求后,AS 会生成一个 [SessionKey_AS],然后根据请求中带有的 [用户名] 信息,从域控的活动目录 AD 中查询该 [用户名] 是否存在,如果存在,那么 AS 还会从活动目录中取出 [用户名] 对应的 [密码],然后 AS 让取出的 [密码] 通过相同的单向 Hash 函数 生成一个密钥 ,然后用这个密钥来解密 时间戳,如果解密成功,则身份验证通过,AS 为 Client 响应如下信息:
-
用 [Client密钥] 加密的 [SessionKey_AS]
-
用 krbtgt hash 加密 [SessionKey_AS] 、 Client ID 、Ticket 有效时间 、Client 网络地址而生成的 TGT票据 (注:Ticket 有效时间即指票据的有效时间,这里票据是TGT,所以 Ticket 有效时间 即为 TGT票据的有效时间)
请求服务授权
1) 客户端向 TGS 发送请求服务授权的请求
Client 收到 AS 响应的信息后,用 [Client密钥] 解密 用 [Client密钥] 加密的 [SessionKey_AS] ,获得 [SessionKey_AS] ,但 Client 无法解密 TGT票据 ,最终会在本地缓存 [SessionKey_AS] 和 TGT票据 。
然后 Client 凭借 TGT票据 向 KDC 发起针对特定 服务S 的 TGS_REQ 请求,请求中带有如下信息:
-
由 AS 为 Client 提供的 TGT票据 ,要请求的 服务S 的 ID ,即 [Service ID]
-
用 [SessionKey_AS] 加密的 Client ID 和 时间戳
2) TGS 为 Client 响应服务授权票据
TGS 收到 Client 请求后,首先会检查自身是否存在客户端请求的服务(就是查询 SPN),如果服务存在,则用 krbtgt hash 解密 TGT票据 得到 [SessionKey_AS] 、 Client ID 、Ticket 有效时间 、Client 网络地址
然后用前面 AS 生成的 [SessionKey_AS] 解密 用 [SessionKey_AS] 加密的 Client ID 和 时间戳 得到 时间戳 和 Client ID
然后 TGS 会比对 时间戳 和 Ticket 有效时间,如果两者和当前时间相差太远,则存在暴力枚举的可能,需要重新认证,并且还会对比解密出的两个 Client ID ,如果相同,则认证成功
认证成功后,TGS 会生成一个 [SessionKey_TGS] ,并响应 Client 如下信息:
-
用 [Service密钥] 加密 [SessionKey_TGS] 、Ticket 有效时间、 Client ID、Client 网络地址而生成的 TGS票据 (TGS 票据也被称为 ST 票据)
-
用 [SessionKey_AS] 加密的 [SessionKey_TGS]
补充: [Service密钥] 是啥 ?
搜索自chatgpt
在 Kerberos 协议中,[Service密钥] 是由网络服务提供方和 TGS 服务器共同维护的一个秘密密钥。它用于对通信内容进行加密,以保护通信内容不被第三方窃取。
[Service密钥] 通常并不是由一个字符串通过 hash 函数加密生成的,而是一个二进制密钥
发送服务请求
1) Client 向 Service Server 发送服务请求
Client 收到 TGS 的响应信息后,得到了 TGS票据 和 用 [SessionKey_AS] 加密的 [SessionKey_TGS]
首先,Client 用本地缓存的 [SessionKey_AS] 解密 用 [SessionKey_AS] 加密的 [SessionKey_TGS] 得到 [SessionKey_TGS],并且将 TGS票据 和 [SessionKey_TGS] 缓存到本地
然后,Client 凭借 TGS票据 去请求 Service Server 上面的 服务S ,请求中带包含下信息:
- TGS票据
-
用 [SessionKey_TGS] 加密的 Client ID 、 时间戳
2) Service Server 响应 Client
Service Server 收到 Client 的请求后,先利用自身的 [Service密钥] 解密 TGS票据 得到 [SessionKey_TGS] 、Ticket 有效时间、 Client ID、Client 网络地址
Service Server 得到 [SessionKey_TGS] 后,利用 [SessionKey_TGS] 解密 用 [SessionKey_TGS] 加密的 Client ID 、 时间戳 得到 Client ID 和 时间戳
Service Server 对比解密出的两个 Client ID ,如果相同,则说明 Client 拥有正确的 [SessionKey_TGS] ,然后用 [SessionKey_TGS] 加密上面解密出的 时间戳 作为 Service Server 向 Client 发出的响应信息
Client 收到了 Service Server 的响应信息后,使用本地缓存的 [SessionKey_TGS] 解密得到 时间戳 ,然后将这个 时间戳 和 1) Client 向 Service Server 发送服务请求 中 用 [SessionKey_TGS] 加密的 Client ID 、 时间戳 中的时间戳进行对比,如果一致,则 Client 开始向 Service Server 发送请求
上面的信息可以看出,该交互过程起到了 Client 与 Service Server 之间的 “双向认证” 作用
Wireshark 分析 Kerberos 协议
分析 AS_REQ、AS_REP、TGS_REQ、TGS_REP 过程
当用户登陆域主机 Windows 系统时,客户端会向 KDC 发起 AS_REQ 请求
现在我们来抓包,虚拟中有两台计算机 ( NAT 模式 )、两个域用户
-
域控:OWA2010CN-God.god.org (192.168.3.21)
-
域内主机:mary-PC.god.org(192.168.3.25)
-
域管理员:god\administrator:Admin12345
-
普通域用户:god\mary:admin!@#45
利用 wireshark 抓 kerberos协议,选择 VMnet8

以 mary 用户登陆 mary-PC.god.org ,登陆成功后,发现 kerberos 协议

第一次 AS-REQ 请求对应的响应信息为 “KRB Error: KRB5KDC_ERR_PREAUTH_REQUIRED”,这是因为在 Kerberos5 之前,Kerberos 允许不使用密码进行身份认证,而在 Kerberos5 中,密码信息不可或缺,这种过程称之为 “预认证”
可能出于向后兼容考虑,Kerberos 在执行预认证之前,首先会尝试不使用密码进行身份认证,因此在登录期间,发送初始 AS-REQ 后我们总是能看到一个错误信息,在这种情况下,攻击者有可能利用 AS-REP Roasting 攻击
然后,我们来分析下 AS_REQ 过程
上图中 msg-type 的所有具体类型和值如下
|
|
上图中 padata 的所有认证信息如下,这里无需纠下面的各种认证信息表示的含义和作用,如果需要答案,可以到 RFC4120 中寻找
|
|
紧接着,分析 AS_REP 过程
然后来分析 TGS_REQ 过程
然后来分析 TGS_REP 过程
最后的 AP_REQ 过程,我们并不能在 wireshark 中找到对应的 AP_REQ 的过程,因为前面在 TGS_REQ 过程中客户端请求的服务是 host 服务,而 host 服务是一种用于身份验证的 本地 服务,所以最后当客户端向 host 服务发送请求时,wireshark 是无法直接抓到数据包的,这里还是有点疑问,但无需深入探究
解密 kerberos 协议中的加密部分
在用 wireshark 抓包时,我们发现 kerberos 协议中很多内容都是加密的,解密过程如下,参考
首先登陆域控 OWA2010CN-God.god.org ,在域控上复制出一份 ntds.dit 文件和 system.hive 文件,这里用卷影复制的方法,复制的时候要和自己的卷影副本卷名对应
先复制出 ntdis.dit 文件,执行 vssadmin create shadow /for=C:

然后执行如下命令
|
|

然后我们进入C盘下,看到了拷贝出的 ntds.dit 文件

然后复制出 system.hive 文件,执行如下命令
|
|

复制完后,删除之前创建的卷影副本 vssadmin delete shadow /all

然后要安装一个 esedbexport 程序,下载地址https://github.com/libyal/libesedb,这里在 kali 中进行编译,执行如下命令
|
|
执行完上面的命令后,可以在 /usr/local/bin 找到 esedbexport 命令,如下:

然后将 ntds.dit 文件复制到 kali 上,执行 esedbexport ntds.dit 命令


然后在 kali 上使用 NTDSXtract 导出需要的 keytab
|
|
运行完上面的命令可以得到 1.keytab

然后打开 wireshark,打开 “编辑”—> “首选项”,选择 “Protocols”,找到 KRB5,勾选 “Try to decrypt Kerberos blobs”,并在下面导入我们刚才生成的 1.keytab,然后就可以对数据包进行解密了

然后 wireshark 过滤器 Vmnet8,再用 mary 用户登陆 mary-PC.god.org ,登陆成功后,我们抓到的 AS_REQ 如下,蓝色部分是解密成功的,解密不成功为黄色

然后我们就可以更详细的来分析 kerberos 协议的各个过程了,这里就不再分析了
参考文章
微信