深入理解 Kerberos 协议 (上)

Kerberos 过程详解

Kerberos 协议通过密钥系统为客户端与服务提供认证服务,为了解决当客户端去访问一个服务器的某服务时,服务器如何判断该对象是否有相关权限来访问自己的服务

客户端用户 A 登陆域成员机,然后访问某个服务,这个过程就涉及到了 kerberos 协议

image-20221208230115006

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

image-20221207215306938

  1. Client 向 KDC 发起 AS_REQ,请求的凭据是 Client hash 加密的时间戳

  2. KDC 使用 Client hash 进行解密,如果结果正确就返回用 krbtgt hash 加密的 TGT 票据,TGT 里面包含 PAC,PAC 包含 Client 的 sid、Client 所在的组

  3. Client 凭借 TGT 票据向 KDC 发起针对特定服务的 TGS_REQ 请求

  4. KDC 使用 krbtgt hash 进行解密,如果结果正确,就返回用服务 hash 加密的 TGS 票据(这一步不管用户有没有访问服务的权限,只要TGT正确,就返回TGS票据)

  5. Client 拿着 TGS 票据去请求服务

  6. 服务使用自己的 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

image-20221208161201934

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

image-20221214113727911

第一次 AS-REQ 请求对应的响应信息为 “KRB Error: KRB5KDC_ERR_PREAUTH_REQUIRED”,这是因为在 Kerberos5 之前,Kerberos 允许不使用密码进行身份认证,而在 Kerberos5 中,密码信息不可或缺,这种过程称之为 “预认证”

可能出于向后兼容考虑,Kerberos 在执行预认证之前,首先会尝试不使用密码进行身份认证,因此在登录期间,发送初始 AS-REQ 后我们总是能看到一个错误信息,在这种情况下,攻击者有可能利用 AS-REP Roasting 攻击

然后,我们来分析下 AS_REQ 过程

2022-12-15_144804-16713670225331-16713670236072-16713828710815.png

上图中 msg-type 的所有具体类型和值如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  Message Type   Value  Meaning

  
  KRB_AS_REQ     10      初始认证请求

  KRB_AS_REP     11      响应 KRB_AS_REQ 请求

  KRB_TGS_REQ    12      基于 TGT 的认证请求

  KRB_TGS_REP    13      响应 KRB_TGS_REQ 请求

  KRB_AP_REQ     14      对服务器的应用程序请求

  KRB_AP_REP     15      对 KRB_AP_REQ_MUTUAL 的响应

  KRB_RESERVED16 16      为用户到用户保留 krb_tgt_request

  KRB_RESERVED17 17      为用户对用户保留 krb_tgt_reply

  KRB_SAFE       20      安全(校验和)应用程序消息

  KRB_PRIV       21      私有(加密)应用程序消息

  KRB_CRED       22      要转发的私有(加密)消息证书

  KRB_ERROR      30      错误响应

上图中 padata 的所有认证信息如下,这里无需纠下面的各种认证信息表示的含义和作用,如果需要答案,可以到 RFC4120 中寻找

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
7.5.2.  PreAuthentication Data Types


   Padata and Data Type    Padata-type   Comment

                            Value


   PA-TGS-REQ                  1

   PA-ENC-TIMESTAMP            2

   PA-PW-SALT                  3

   [reserved]                  4

   PA-ENC-UNIX-TIME            5        (deprecated)

   PA-SANDIA-SECUREID          6

   PA-SESAME                   7

   PA-OSF-DCE                  8

   PA-CYBERSAFE-SECUREID       9

   PA-AFS3-SALT                10

   PA-ETYPE-INFO               11

   PA-SAM-CHALLENGE            12       (sam/otp)

   PA-SAM-RESPONSE             13       (sam/otp)

   PA-PK-AS-REQ_OLD            14       (pkinit)

   PA-PK-AS-REP_OLD            15       (pkinit)

   PA-PK-AS-REQ                16       (pkinit)

   PA-PK-AS-REP                17       (pkinit)

   PA-ETYPE-INFO2              19       (replaces pa-etype-info)

   PA-USE-SPECIFIED-KVNO       20

   PA-SAM-REDIRECT             21       (sam/otp)

   PA-GET-FROM-TYPED-DATA      22       (embedded in typed data)

   TD-PADATA                   22       (embeds padata)

   PA-SAM-ETYPE-INFO           23       (sam/otp)

   PA-ALT-PRINC                24       (crawdad@fnal.gov)

   PA-SAM-CHALLENGE2           30       (kenh@pobox.com)

   PA-SAM-RESPONSE2            31       (kenh@pobox.com)

   PA-EXTRA-TGT                41       Reserved extra TGT

   TD-PKINIT-CMS-CERTIFICATES  101      CertificateSet from CMS

   TD-KRB-PRINCIPAL            102      PrincipalName

   TD-KRB-REALM                103      Realm

   TD-TRUSTED-CERTIFIERS       104      from PKINIT

   TD-CERTIFICATE-INDEX        105      from PKINIT

   TD-APP-DEFINED-ERROR        106      application specific

   TD-REQ-NONCE                107      INTEGER

   TD-REQ-SEQ                  108      INTEGER

   PA-PAC-REQUEST              128      (jbrezak@exchange.microsoft.com)

紧接着,分析 AS_REP 过程

2022-12-15_160022-16713724086413-16714146850886.png

然后来分析 TGS_REQ 过程

2022-12-15_165608-16714150028837.png

然后来分析 TGS_REP 过程

2022-12-15_180943-16714155104218.png

最后的 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:

image-20221216185951498

然后执行如下命令

1
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\NTDS\NTDS.dit C:\ntds.dit

image-20221216190245666

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

image-20221216190548163

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

1
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\system.hiv

image-20221216191726086

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

image-20221216191950049

然后要安装一个 esedbexport 程序,下载地址https://github.com/libyal/libesedb,这里在 kali 中进行编译,执行如下命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
wget https://github.com/libyal/libesedb/releases/download/20210424/libesedb-experimental-20210424.tar.gz
tar -xzvf libesedb-experimental-20210424.tar.gz
cd libesedb-20210424/
sudo apt-get install autoconf automake autopoint libtool pkg-config

#安装依赖包
./configure
make
make install
sudo ldconfig

执行完上面的命令后,可以在 /usr/local/bin 找到 esedbexport 命令,如下:

image-20221216204656027

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

image-20221216205335978

image-20221216205451218

然后在 kali 上使用 NTDSXtract 导出需要的 keytab

1
2
3
4
5
git clone https://github.com/csababarta/ntdsxtract.git
cd ntdsxtract/
python2 dskeytab.py ntds.dit.export/datatable.3 /ntds.dit.export/link_table.5 system.hive /usr/local/bin/ntdsxtract/ 1.keytab

#注意:运行dskeytab.py要用python2来运行,并且要提前安装相对应的库 pip2 install pycryptodome 

运行完上面的命令可以得到 1.keytab

image-20221216221829376

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

image-20221216222712442

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

image-20221216222405147

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

参考文章

一文了解黄金票据和白银票据

Kerberos概述及常见攻击场景

windows-protocol

Kerberos 认证过程详细分析

域渗透-Kerberos认证

kerberos认证协议爱情故事

由浅入深理解Kerberos协议

通过将keytab导入wireshark中实现对Kerberos协议加密部分进行直接解包

kerberos协议从0到1

 微信 微信
0%