内网渗透学习—kerberos协议

kerberos协议中的角色与简单流程

Kerberos是一种由MIT(麻省理工大学)提出的一种网络身份验证协议。它旨在通过使用密钥加密技术为客户端/服务器应用程序提供强身份验证。

在kerberos协议之中主要是有三个角色存在:

  • Client(用户):发出访问服务的角色
  • Server(服务):提供服务的角色
  • KDC(Key Distribution Center)密钥分发中心:分发密钥的角色

在一个域林之中,KDC服务默认会安装在域控之中,而client和server是域内的用户或者服务。在kerberos认证过程中client是否有权限访问server的服务就由KDC发放的票据决定

简化的Kerberos认证流程图

名词概念

AD(Account Datebase):账户数据库

Master Key: 用户密码的一种hash值

Ticket(票据):域网络对象相互访问的凭证

TGT(Ticket Granting Ticket 票据授予票据):用于向KDC获取服务票据的凭证

TGS(Silver Ticket 服务票据):用于向Server请求服务的凭证

Authentication Service(身份认证服务):认证Client 的身份,并为其发放TGT的服务,是KDC的一部分

Ticket Granting Service(票据发放服务):检验Client发来的TGT,并为其生成某个Server的TGS,是KDC的一部分。

image-20201106001335990

  1. AS_REQ(认证服务请求):Client向KDC发送AS_REQ,请求的凭据是Client的hash(这个hash是根据输入的密码生成的)加密的时间戳。
  2. AS_REP(认证服务响应):KDC向发出AS_REQ的Client发出响应,去如果认证成功就返回一个TGT
  3. TGS_REQ(票据发放服务请求):Client凭借TGT向KDC发送对某一Server的TGS_REQ
  4. TGS_REP(票据发放服务响应):KDC验证TGT,如果验证正确就根据请求的服务返回对应的TGS,不管是否有权向访问Server
  5. AP_REQ(服务请求):Client凭借TGS向Server发起服务请求
  6. AP_REP(服务响应):Server验证TGS,如果验证正确就向KDC询问,Client是否有权限获得服务,如果有就返回响应

AS_REQ

数据包结构拆解

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
Kerberos
Record Mark: 294 bytes
0... .... .... .... .... .... .... .... = Reserved: Not set
.000 0000 0000 0000 0000 0001 0010 0110 = Record Length: 294
as-req
pvno: 5
msg-type: krb-as-req (10)
padata: 2 items
PA-DATA PA-ENC-TIMESTAMP
padata-type: kRB5-PADATA-ENC-TIMESTAMP (2)
padata-value: 3041a003020112a23a04384e3857102e1da38ea37695b42c…
etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
cipher: 4e3857102e1da38ea37695b42cc877f2dfbc29a67c6c8f21…
PA-DATA PA-PAC-REQUEST
padata-type: kRB5-PADATA-PA-PAC-REQUEST (128)
padata-value: 3005a0030101ff
include-pac: True
req-body
Padding: 0
kdc-options: 40810010
0... .... = reserved: False
.1.. .... = forwardable: True
..0. .... = forwarded: False
...0 .... = proxiable: False
.... 0... = proxy: False
.... .0.. = allow-postdate: False
.... ..0. = postdated: False
.... ...0 = unused7: False
1... .... = renewable: True
.0.. .... = unused9: False
..0. .... = unused10: False
...0 .... = opt-hardware-auth: False
.... 0... = unused12: False
.... .0.. = unused13: False
.... ..0. = constrained-delegation: False
.... ...1 = canonicalize: True
0... .... = request-anonymous: False
.0.. .... = unused17: False
..0. .... = unused18: False
...0 .... = unused19: False
.... 0... = unused20: False
.... .0.. = unused21: False
.... ..0. = unused22: False
.... ...0 = unused23: False
0... .... = unused24: False
.0.. .... = unused25: False
..0. .... = disable-transited-check: False
...1 .... = renewable-ok: True
.... 0... = enc-tkt-in-skey: False
.... .0.. = unused29: False
.... ..0. = renew: False
.... ...0 = validate: False
cname
name-type: kRB5-NT-PRINCIPAL (1)
cname-string: 1 item
CNameString: testuser
realm: HACKE
sname
name-type: kRB5-NT-SRV-INST (2)
sname-string: 2 items
SNameString: krbtgt
SNameString: HACKE
till: 2037-09-13 02:48:05 (UTC)
rtime: 2037-09-13 02:48:05 (UTC)
nonce: 19228112
etype: 6 items
ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
ENCTYPE: eTYPE-AES128-CTS-HMAC-SHA1-96 (17)
ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5 (23)
ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5-56 (24)
ENCTYPE: eTYPE-ARCFOUR-HMAC-OLD-EXP (-135)
ENCTYPE: eTYPE-DES-CBC-MD5 (3)
addresses: 1 item WIN10-X64-TEST<20>
HostAddress WIN10-X64-TEST<20>
addr-type: nETBIOS (20)
NetBIOS Name: WIN10-X64-TEST<20> (Server service)
  • pvno

kerberos版本号

  • msg-type

windows消息类型,AS_REQ的自然是krb-as-req

  • padata(pre-authentication data 预认证数据)

是一些认证信息,是一个列表,内部有若干个认证消息,每一个认证消息有type和value。

具体可看:Kerberos PA-DATA

  • req-body

    • kdc-options

    这是一些KDC的option开启情况,属于一种标识位。 mit文档

    • cname

    这是Client的主机名,采用的是PrincipalName 类型和string类型的组合。sname也是采用这种格式

    PrincipalName 类型

    KRB_NT_PRINCIPAL 用户主体名称类型

    KRB_NT_SRV-INST 服务和其他唯一实例(krbtgt)的名称类型

    KRB_NT_SRV_HST 服务主机名称为实例名的名称类型

    KRB_NT_SRV_XHST 服务与主机作为剩余组件名称类型

    KRB_NT_UID 唯一ID名称类型

    KRB_NT_UNKNOWN 未知名称类型

    • realm

    服务端域名

    • sname

    这是是服务端的身份和所属域,注意在AS_REQ中服务端指的是提供AS的KDC,所以正常的sname-string字段的值就应该是krbtgt和其所属域.

    • till

    到期时间

    • etype

    加密类型,在请求报文之中每个有加密的数据都有一个etype字段对应,KDC就是从这段数据中加密方式,来从AD之中选择对应的hash来进行身份验证

    • addresses

    地址相关信息@

KDC接收AS_REQ的行为

两个重要的padata(pre-authentication data 预认证数据)

PA-ENC-TIMESTAMP

这个预认证数据是Client用自己的Master key加密时间戳得到的一串字符, AS拿到这个段数据之后就会根据etype去AD里面寻找对应的用户hash(用户名取自cname),并使用这个hash解密时间戳, 如果解密成功, 并且时间戳在一定范围之内,则这个预认证数据通过.

PA-PAC-REQUEST

这个预认证数据是关于微软的一个扩展—PAC, 这个扩展的基本作用就是为kerberos添加”权限认证”的能力. 开启这项扩展,AS完成时间戳的认证之后就会将PAC(内部包涵Client的sid和所在组)放TGT的认证数据之中, 一起返回给Client, PAC关系到之后Server判断Client是否有权限访问服务

AS_REP

拆解数据包

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
Kerberos
Record Mark: 1550 bytes
0... .... .... .... .... .... .... .... = Reserved: Not set
.000 0000 0000 0000 0000 0110 0000 1110 = Record Length: 1550
as-rep
pvno: 5
msg-type: krb-as-rep (11)
padata: 1 item
PA-DATA PA-ENCTYPE-INFO2
padata-type: kRB5-PADATA-ETYPE-INFO2 (19)
padata-value: 3020301ea003020112a1171b154841434b452e544553544c…
ETYPE-INFO2-ENTRY
etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
salt: HACKE.TESTLABtestuser
crealm: HACKE.TESTLAB
cname
name-type: kRB5-NT-PRINCIPAL (1)
cname-string: 1 item
CNameString: testuser
ticket
tkt-vno: 5
realm: HACKE.TESTLAB
sname
name-type: kRB5-NT-SRV-INST (2)
sname-string: 2 items
SNameString: krbtgt
SNameString: HACKE.TESTLAB
enc-part
etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
kvno: 2
cipher: 07b5d35de5b1ac006b831ff508a5ced14a010563418fd736…
enc-part
etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
kvno: 4
cipher: 70246fe54be2b6395f20dc6845b970d16bb3319ab304e3bb…

主要关注与AS_REQ不同的点

  • ticket

    这就是AS派发的TGT票据,内部所有密文的密钥都是krbtgtNTLM hash,如果能拿到krbtgtNTLM hash我们既可以伪造TGT,这就是黄金票据

    • tkt-vno

      票据版本

    • realm

      派发票据的KDC的所属域

    • sname

      派发票据的角色再KDC的身份,一般是kbrtgt

    • enc-part

      使用kbrtgtNTLM hash作为密钥生成的TGT主体

  • enc-part

    这部分是使用Client的hash为key加密Session key得到的,主要用于作为下阶段(TGS阶段)的认证密钥。

AS阶段的安全问题

用户名枚举

在AS认证截断,用户名存在和密码错误的响应报文错误码不同,

  • 用户名不存在的响应错误码是6:KDC_ERR_C_PRINCIPAL_UNKNOWN 未知的主机名

  • 密码错误,用户名存在的响应错误码是24:KDC_ERR_PREAUTH_PAILED 预认证失败

通过这个比较AS_REP里的错误码就可实行 用户名枚举 .

黄金票据

AS_ERP里的tikcet的encpart是使用kbrtgtNTLM hashkey加密而成的,所以只要拿到了kbrtgtNTLM hash就可以伪造TGT,这个伪造出来的票据就叫做 黄金票据

TGS_REQ

拆解数据包

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
Frame 40: 62 bytes on wire (496 bits), 62 bytes captured (496 bits) on interface \Device\NPF_{FBDB2B2D-DEF3-473C-87EF-787E4B606694}, id 0
Ethernet II, Src: VMware_f0:d8:2b (00:0c:29:f0:d8:2b), Dst: VMware_e6:ab:e6 (00:0c:29:e6:ab:e6)
Internet Protocol Version 4, Src: 192.168.1.2, Dst: 192.168.1.1
Transmission Control Protocol, Src Port: 49731, Dst Port: 88, Seq: 1461, Ack: 1, Len: 8
[2 Reassembled TCP Segments (1468 bytes): #39(1460), #40(8)]
Kerberos
Record Mark: 1464 bytes
tgs-req
pvno: 5
msg-type: krb-tgs-req (12)
padata: 2 items
PA-DATA PA-TGS-REQ
padata-type: kRB5-PADATA-TGS-REQ (1)
padata-value: 6e8204f4308204f0a003020105a10302010ea20703050000…
PA-DATA PA-PAC-OPTIONS
padata-type: kRB5-PADATA-PAC-OPTIONS (167)
padata-value: 3009a00703050040000000
req-body
Padding: 0
kdc-options: 40810000
0... .... = reserved: False
.1.. .... = forwardable: True
..0. .... = forwarded: False
...0 .... = proxiable: False
.... 0... = proxy: False
.... .0.. = allow-postdate: False
.... ..0. = postdated: False
.... ...0 = unused7: False
1... .... = renewable: True
.0.. .... = unused9: False
..0. .... = unused10: False
...0 .... = opt-hardware-auth: False
.... 0... = unused12: False
.... .0.. = unused13: False
.... ..0. = constrained-delegation: False
.... ...1 = canonicalize: True
0... .... = request-anonymous: False
.0.. .... = unused17: False
..0. .... = unused18: False
...0 .... = unused19: False
.... 0... = unused20: False
.... .0.. = unused21: False
.... ..0. = unused22: False
.... ...0 = unused23: False
0... .... = unused24: False
.0.. .... = unused25: False
..0. .... = disable-transited-check: False
...0 .... = renewable-ok: False
.... 0... = enc-tkt-in-skey: False
.... .0.. = unused29: False
.... ..0. = renew: False
.... ...0 = validate: False
realm: HACKE.TESTLAB
sname
name-type: kRB5-NT-SRV-HST (3)
sname-string: 2 items
SNameString: host
SNameString: win10-x64-test.hacke.testlab
till: 2037-09-13 02:48:05 (UTC)
nonce: 19595592
etype: 5 items
ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
ENCTYPE: eTYPE-AES128-CTS-HMAC-SHA1-96 (17)
ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5 (23)
ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5-56 (24)
ENCTYPE: eTYPE-ARCFOUR-HMAC-OLD-EXP (-135)
  • msg-type

    windows消息格式,krb-tgs-req

  • padata

    这部分携带了TGS_REQ最重要的数据—TGT票据,TGT票据以ap-req的形式存放在数据包之中。KDC会校验TGT,如果正确就返回TGS票据

    这部分数据和还包含PAC和S4U2SELF,这个之后其他文章单独说

  • req-body

    格式和之前的请求报文基本一致,只是这里的sname换成了Client想要请求服务的Server的名字

TGS_REP

数据包拆解

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
Kerberos
Record Mark: 1495 bytes
0... .... .... .... .... .... .... .... = Reserved: Not set
.000 0000 0000 0000 0000 0101 1101 0111 = Record Length: 1495
tgs-rep
pvno: 5
msg-type: krb-tgs-rep (13)
crealm: HACKE.TESTLAB
cname
name-type: kRB5-NT-PRINCIPAL (1)
cname-string: 1 item
CNameString: testuser
ticket
tkt-vno: 5
realm: HACKE.TESTLAB
sname
name-type: kRB5-NT-SRV-HST (3)
sname-string: 2 items
SNameString: host
SNameString: win10-x64-test.hacke.testlab
enc-part
etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
kvno: 1
cipher: 1fc40f7b907bea22e5606abf4f0575c113b8f5ee8d87ce4f…
enc-part
etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
cipher: e4705cfafb271944be50c33f4576bb4b4e449357fbdbb18f…
  • msg-type

    windows消息格式,krb-tgs-rep

  • crealm

    Client所属域

  • cname

    Client的身份名

  • ticket

    这就是最终的票据,是使用Client请求服务的Server的hash作为key来加密得到的。内部包含:Server session keyClient info (Domain name\client)end time (到期时间)

  • enc-part

    这一部分是使用AS认证中得Session key为key加密成得内部有Server session key,主要用于下轮用户认证(AP阶段)

参考连接:

https://daiker.gitbook.io/windows-protocol/