KERBEROS详解

KERBEROS详解

概述

在Kerberos协议中主要是有三个角色的存在:

  1. 访问服务的Client(以下表述为Client 或者用户)
  2. 提供服务的Server(以下表述为服务)
  3. KDC(Key Distribution Center)密钥分发中心 kerberos 测试工具介绍

其中KDC服务默认会安装在一个域的域控中,而Client和Server为域内的用户或者是服务,如HTTP服务,SQL服务。在Kerberos中Client是否有权限访问Server端的服务由KDC发放的票据来决定。

image-20210126111431232

  1. ASREQ: Client向KDC发起ASREQ,请求凭据是Client hash加密的时间戳
  2. AS_REP: KDC使用Client hash进行解密,如果结果正确就返回用krbtgt hash加密的TGT票据,TGT里面包含PAC,PAC包含Client的sid,Client所在的组。
  3. TGSREQ: Client凭借TGT票据向KDC发起针对特定服务的TGSREQ请求
  4. TGS_REP: KDC使用krbtgt hash进行解密,如果结果正确,就返回用服务hash 加密的TGS票据(这一步不管用户有没有访问服务的权限,只要TGT正确,就返回TGS票据)
  5. AP_REQ: Client拿着TGS票据去请求服务
  6. AP_REP: 服务使用自己的hash解密TGS票据。如果解密正确,就拿着PAC去KDC那边问Client有没有访问权限,域控解密PAC。获取Client的sid,以及所在的组,再根据该服务的ACL,判断Client是否有访问服务的权限。

AS_REQ

字段

  • pvno:kerberos 版本号

  • msg_type:类型,ASREQ对应的就是KRBAS_REQ(0x0a)

  • PA_DATA:认证信息(在这个阶段主要关注两个字段)

    • ENC_TIMESTAMP

      这个是预认证,就是用用户hash加密时间戳,作为value 发送给AS服务器。然后AS服务器那边有用户hash,使用用户hash进行解密,获得时间戳,如果能解密,且时间戳在一定的范围内,则证明认证通过

    • PAPACREQUEST

      这个是启用PAC支持的扩展。PAC(Privilege Attribute Certificate)并不在原生的kerberos里面,是微软引进的扩展。PAC包含在ASREQ的响应body(ASREP)。这里的value对应的是include=true或者include=false(KDC根据include的值来判断返回的票据中是否携带PAC)。

  • REQ_Body:flag字段

    • cname:请求的用户,这个用户名存在和不存在,返回的包有差异,可以用于枚举域内用户名

      1
      2
      3
      4
      5
      PrincipalName 类型。# PrincipalName包含type和value。

      KRBNTPRINCIPAL = 1 # means just the name of the principal 如daizhibin
      KRBNTSRV_INST = 2 # service and other unique instance (krbtgt) 如krbtgt,cifs
      KRBNTENTERPRISE_PRINCIPAL = 10 # 如 user@domain.com
    • sname:在ASREQ里面sname是krbtgt,类型是KRBNTSRVINST

      剩下的还有:

      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
      realm:域名

      from:发送时间

      till:到期时间,rubeus和kekeo都是20370913024805Z,这个可以作为特征来检测工具。

      nonce:随机生成的一个数kekeo/mimikatz nonce是12381973,rubeus nonce是1818848256,这个也可以用来作为特征检测工具。

      etype:加密类型,有以下:
      des_cbc_crc = 1,
      des_cbc_md4 = 2,
      des_cbc_md5 = 3,
      des3_cbc_md5 = 5,
      des3_cbc_sha1 = 7,
      dsaWithSHA1_CmsOID = 9,
      md5WithRSAEncryption_CmsOID = 10,
      sha1WithRSAEncryption_CmsOID = 11,
      rc2CBC_EnvOID = 12,
      rsaEncryption_EnvOID = 13,
      rsaES_OAEP_ENV_OID = 14,
      des_ede3_cbc_Env_OID = 15,
      des3_cbc_sha1_kd = 16,
      aes128_cts_hmac_sha1 = 17,
      aes256_cts_hmac_sha1 = 18,
      rc4_hmac = 23,
      rc4_hmac_exp = 24,
      subkey_keymaterial = 65

      AS_REP

字段

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

  • msg-type:ASREQ的响应body对应的就是KRBAS_REP(0x0b)

  • crealm:域名

  • cname:用户名

  • ticket:这个ticket用于TGSREQ的认证(TGT)。是加密的,用户不可读取里面的内容(因为是使用krbtgt的hash进行加密的)。因此如果我们拥有krbtgt的hash就可以自己制作一个ticket,既黄金票据。

  • enc_part:这部分是可以解密的,key是用户hash,解密后得到Encryptionkey,Encryptionkey里面最重要的字段是session key,作为下阶段的认证密钥

TGT

凭据里面最核心的东西是session-key和加密的ticket。

正常我们用工具生成的凭据是.ccache和.kirbi后缀的,用mimikatz,kekeo,rubeus生成的凭据是以.kirbi后缀的。impacket 生成的凭据的后缀是.ccache。两种票据主要包含的都是session-key和加密的ticket,因此可以相互转化。

以kirbi为例介绍下该结构体。

1
2
3
4
5
6
 KRB-CRED::= [APPLICATION 22] SEQUENCE {
pvno[0] INTEGER(5),
msg-type[1] INTEGER(22),
tickets[2] SEQUENCE OF Ticket,
enc-part[3] EncryptedData -- EncKrbCredPart
}

其中ticket来自于KRBASREP部分的ticket

1
2
3
4
5
6
7
8
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部分的主要内容是session-key,来自于用户hash解密enc_part的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
KrbCredInfo     ::= SEQUENCE {
key [0] EncryptionKey, sessionKey
prealm [1] Realm OPTIONAL, # 对应的是realm
pname [2] PrincipalName OPTIONAL, # 对应的是cname
flags [3] TicketFlags OPTIONAL,
authtime [4] KerberosTime OPTIONAL, # not require
starttime [5] KerberosTime OPTIONAL,
endtime [6] KerberosTime OPTIONAL,
renew-till [7] KerberosTime OPTIONAL,
srealm [8] Realm OPTIONAL, # 对应的是realm
sname [9] PrincipalName OPTIONAL, # 对应的是sname
caddr [10] HostAddresses OPTIONAL
}

TGSREQ

TGSREQ这个阶段不需要账号密码,需要ASREP获取到的TGT凭据。需指定域控地址

字段

  • msg-type:类型,TGSREQ对应的就是KRBTGS_REQ(0x0c)

  • PA-DATA:认证信息

    • AP_REQ

      上一轮请求获得的TGT票据

    • PAFORUSER

      请求类型:S4U2SELF,值为请求用户的用户名

    • PAPACOPTIONS

      1
      2
      3
      4
      5
      6
      7
      8
      9
      包含标记位如下:

      Claims(0)

      Branch Aware(1)

      Forward to Full DC(2)

      Resource-based Constrained Delegation (3)

      基于资源的约束委派需要指定Resource-based Constrained Delegation位

  • REQ_BODY

    • sname

      请求的服务名(返回的tgs是使用服务用户的hash进行加密的)

    • AddtionTicket

      附加票据,约束委派时,需要正常的TGT以及S4Uself获得的TGS,TGS存入additionticket

TGS_REP

字段

  • msg-type:ASREQ的响应body对应的就是KRBTGS_REQ(0x0d)

  • ticket:和APREQ返回的ticket很像,使用服务用户的hash加密

  • enc_part:可解密,密钥为AS_REP返回的session_key,得到encryptionkey,其中包含另一个session_key,作为下一个阶段的密钥

S4U2SELF

S4U2self 使得服务可以代表用户获得针对服务自身的kerberos服务票据。这使得服务可以获得用户的授权( 可转发 的用户TGS票据),然后将其用于后期的认证(主要是后期的s4u2proxy),这是为了在用户以不使用 Kerberos 的方式对服务进行身份验证的情况下使用

img

  • 条件:服务拥有自己的tgt

  • 前文的 PAFORUSER 类型为S4U2SELF,*cname*** 与 *snmae*** 都为服务名。若服务请求了可转发,则当

    • TGT可转发
    • 服务配置了约束委派

    时,TGS设置可转发字段。

  • 若用户设置了不允许委派,则S4U2SELF返回的票据是永远不可转发的。

S4U2PROXY

使得服务1可以使用返回的ST代表用户请求服务2的ST并访问该服务

img

  • 如前文所述将st放入additionkey
  • 在请求的kdc-options中设置CNAME-IN-ADDL-TKT标志
  • 同样需要请求可转发
  • sname为服务2的spn
  • 若additionkey的票据不可转发但是服务1配置了对服务2的基于资源的约束委派,返回的票据依然可转发(PA-PAC-OPTION设置了Resource-Based Constrained Delegation标志位)

安全问题

pth/ptk

在进行认证的时候,是用用户hash加密时间戳,即使在使用密码进行登录的情况下,也是先把密码加密成hash,再进行认证。因此在只有用户hash,没有明文密码的情况下也是可以进行认证的。不管是rubeus还是impacket里面的相关脚本都是支持直接使用hash进行认证。其中,如果hash的ntlm hash,然后加密方式是rc4,这种就算做是pass the hash,如果是hash是aes key(使用 sekurlsa::ekeys 导出来),就算是pass the key。在很多地方,不支持rc4加密方式的时候,使用pass the key不失为一种好方法。

用户名枚举

因为在req包中当cname字段的用户名存在与否所对应的返回值是不同的,故可用以枚举用户名

用户名存在:

img

用户名不存在:

img

AS_REPROASTING

域用户如果设置了选项”Do not require Kerberos preauthentication”,此时向域控制器的88端口发送ASREQ请求,对收到的ASREP内容(enc-part底下的ciper,因为这部分是使用用户hash加密session-key,我们通过进行离线爆破就可以获得用户hash)重新组合,能够拼接成”Kerberos 5 AS-REP etype 23”(18200)的格式,接下来可以使用hashcat对其破解,最终获得该用户的明文口令

img

获取AS_REP里面enc-part部分里面的ciper,然后组装成前面32位16进制字符+$+后面的16进制字符得到repHash,然后format(“$krb5asrep$23${0}@{1}:{2}”, userName, domain, repHash)得到字符串,交给hashcat 破解就行

黄金票据

这就没啥好说的了吧

ptt

通过票据传递来通过身份认证

kerberoasting

TGSREP返回的ticket是通过服务用户的hashs加密的,因此可以通过爆破获得服务用户的口令。而当用户向kdc请求ST时,只要TGT正确,无论用户是否有访问服务的权限,都会返回ST。因此可通过此方法爆破服务用户的口令

  • TGSREQ 的 sname 为spn
  • 然后按照format(“$krb5tgs${0}${1}${2}${3}${4}${5}”, encType, userName, domain, spn, cipherText.Substring(0, 32), cipherText.Substring(32))就可以拼接处hash cat(13100)能跑的hash。

白银票据

也没什么好说的吧

委派

详见委派的文章

工具

Rubeus

  • as_reproastrubeus.exe asreproast

impacket

  • GetNPUsers.py:查找设置不需要预认证的用户并列出tgt

    img

KERBEROAST

1
2
3
4
5
6
7
8
9
10
11
12
# 导出spn
> setspn -Q */*

# 请求票据
> Add-Type -AssemblyName System.IdentityModel
> New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "MSSQLSvc/sqlserver.jmu.com:1433"

# 导出票据
mimikatz "kerberos::list /export"

# 爆破
> python tgsrepcrack.py wordlist.txt 1-MSSQLSvc~sql01.medin.local~1433-MYDOMAIN.LOCAL.kirbi

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!