Kerberos协议

windows域渗透必看协议之Kerberos协议

Kerberos介绍

kerberos是一种网络认证协议,他能够为网络中通信的双方提供严格的身份验证服务,确保通信双方身份的真实性和安全性。

kerberos协议有三个角色:用户(client)、服务器(Server)和KDC(Key Distribute Center、密钥分发中心)。

其中,KDC包括AS(Authentication Server,认证服务器)和TGS(Ticket Granting Server、票据授权服务器)。

  • AS,认证服务器,专门用来认证客户端的身份并发放客户用于访问TGS的TGT(票据授予票据)
  • TGS,票据授予服务器,用来发放整个认证过程以及客户端访问服务端时所需的服务授予票据(Ticket)

Kerberos认证协议是基于票据的一种认证方式。在域环境中,KDC服务部署在控制器DC上,而Client和Server为域内的用户或者是服务,如HTTP服务,SQL服务。在Kerberos中Client是否有权限访问Server端的服务由KDC发放的票据来决定。

kerberos认证过程如下:

  1. AS_REQ:Client向AS发起AS_REQ,请求凭据是Client hash加密的时间戳
  2. AS_REP:AS使用Client hash进行解密,如果结果正确就返回用krbtgt hash加密的TGT票据,TGT里面包含PAC,PAC包含Client的sid、Client所在的组。除此之外AS会生成一个临时秘钥Session-Key,并使用客户端的 NTLM-Hash加密Session-key作为响应包的一部分内容。
  3. TGS_REQ:Client凭借TGT票据向TGS发起针对特定服务的TGS_REQ请求
  4. TGS_REP:TGS使用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和AS-REP

在AS-REQ和AS-REP阶段,Client向AS发起AS_REQ,请求内容为通过Client的哈希加密的时间戳。AS使用Client的hash进行解密,如果结果正确就返回用krbtgt hash加密的TGT票据,TGT里面包含PAC,PAC包含Client的sid、Client所在的组。除此之外AS会生成一个临时秘钥Session-Key,并使用客户端的 NTLM-Hash加密Session-key作为响应包的一部分内容。

AS-REQ

Client向AS发起AS_REQ,请求凭据是Client hash加密的时间戳,请求凭据放在padata中。

以下是wireshark抓的AS-REQ数据包

pvno:kerberos版本号

msg-type:消息类型,AS_REQ对应的就是KRB_AS_REQ(0x0a)

padata:主要是一些认证信息。一个列表,包含若干个认证消息用于认证,我们也可以Authenticator。每个认证消息有type和value。

在AS-REQ阶段,用到了ENC_TIMESTAMPPA_PAC_REQUEST

ENC_TIMESTAMP:用于预认证。使用用户hash加密时间戳,作为value 发送给AS服务器。然后AS服务器那边有用户hash,使用用户hash进行解密,获得时间戳,如果能解密,且时间戳在一定的范围内,则证明认证通过。
PA_PAC_REQUEST:是否启用PAC支持的扩展。PAC(Privilege Attribute Certificate)并不在原生的kerberos里面,是微软引进的扩展。PAC包含在AS_REQ的响应body中。这里的value对应的是include-pac=true或者include-pac=false(KDC根据include的值来判断返回的票据中是否携带PAC)

req-body:请求的具体数据

  • kdc-options:请求的标志位

  • cnamePrincipalName类型。PrincipalName包含typevalue

    KRB_NT_PRINCIPAL = 1:means just the name of the principal,如dailker
    KRB_NT_SRV_INST = 2 service and other unique instance (krbtgt) ,如krbtgt,cifs
    KRB_NT_ENTERPRISE_PRINCIPAL = 10user@domain.com
    在AS_REQ里面cname是请求的用户,这个用户名存在和不存在,返回的包有差异,可以根据这个枚举域内用户名。

  • realm:域名

  • snamePrincipalName 类型。

    在AS_REQ里面sname是krbtgt,类型是KRB_NT_SRV_INST

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

  • etype:加密类型。AS是通过AS_REQ中的etype加密类型来选择对应用户的Hash进行解密的,在认证的时候也是会通过明文密码的Hash值进行加密时间戳

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

AS-REP

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

msg-type:消息类型,AS_REP对应的就是KRB_AS_REP(0x0b)

crealm:域名

cname:用户名

ticket:用于TGS_REQ的认证。是加密的,用户不可读取里面的内容。

在AS_REQ请求里面是,是使用krbtgt的hash进行加密的,因此如果我们拥有krbtgt的hash就可以自己制作一个ticket,既黄金票据。
ticket中有如下字段:tkt-vno、realm、sname、enc-part(用krbtgt的hash加密的票据部分)
enc_part:这部分是可以解密的,key是用户hash,解密后得到Encryptionkey,Encryptionkey里面最重要的字段是session key,作为下阶段的认证密钥。

TGS-REQ和TGS-REP

在TGS_REQ和TGS_REP阶段,用户通过AS_REP拿到的TGT票据,去向KDC申请特定服务的访问权限,KDC校验TGT票据,如果校验通过的话,会向用户发送一个TGS票据,之后用户再拿着TGS去访问特定的服务。

TGS-REQ

msg-type:请求类型,TGS_REQ对应的就是KRB_TGS_REQ(0x0c)

padata:携带的一些数据

  • PA-TGS-REQ:这个是TGS_REQ必须携带的部分,这部分会携带AS_REP里面获取到的TGT票据。KDC校验TGT票据,如果票据正确,就返回TGS票据。
  • PA-PAC-OPTIONS:类型是 PA_PAC_OPTIONS,S4U2proxy则必须扩展PA-PAC-OPTIONS结构。
    如果是基于资源的约束委派,就需要指定Resource-based Constrained Delegation位
  • PA_FOR_USER:类型是S4U2SELF,值是一个唯一的标识符,该标识符指示用户的身份。

    该唯一标识符由用户名和域名组成。
    S4U2proxy 必须扩展PA_FOR_USER结构,指定服务代表某个用户去请求针对服务自身的kerberos服务票据。

req-body

  • sname:要请求的服务,TGS_REP获得的ticket是用该服务用户的hash进行加密的。

    有个比较有意思的特性是,如果指定的服务是krbtgt,那么拿到的TGS票据是可以当做TGT票据用的

  • AddtionTicket:附加票据。在S4U2proxy请求里面,既需要正常的TGT,也需要S4U2self阶段获取到的TGS,那么这个TGS就添加到AddtionTicket里面

TGS_REP

TGS使用krbtgt hash进行解密,如果结果正确,就返回用服务hash加密的TGS票据

msg-type:TGS_REQ的响应body对应的就是KRB_TGS_REQ(0x0d)

ticket:这个ticket用于AP_REQ的认证。其中里面的enc_part是加密的,用户不可读取里面的内容。

在AS_REQ请求里面是,是使用krbtgt的hash进行加密的,而在TGS_REQ里面是使用要请求的服务的hash加密的。因此如果我们拥有服务的hash就可以自己制作一个ticket,既白银票据。

enc_part:这部分是可以解密的,key是上一轮AS_REP里面返回的session_key,解密后得到encryptionkey,encryptionkey这个结构里面最重要的字段也是session_key(但是这个session_key不同于上一轮里面的session_key),用来作为作为下阶段的认证密钥。

PAC

在引入PAC前,kerberos的流程是这样的:
1、用户向KDC发起AS_REQ,请求凭据是用户hash加密的时间戳,KDC使用用户hash进行解密,如果结果正确返回用krbtgt hash加密的TGT票据
2、用户凭借TGT票据向KDC发起针对特定服务的TGS_REQ请求,KDC使用krbtgt hash进行解密,如果结果正确,就返回用服务hash 加密的TGS票据
3、用户拿着TGS票据去请求服务,服务使用自己的hash解密TGS票据。如果解密正确,就允许用户访问。

上述流程忽略一个最重要的因素,那就是用户有没有权限访问该服务。在上面的流程里面,只要用户的hash正确,那么就可以拿到TGT,有了TGT,就可以拿到TGS,有了TGS,就可以访问服务。因此,任何一个用户都可以访问任何服务。

也就是说上面的流程解决了”Who am i?”的问题,并没有解决 “What can I do?”的问题。

为了解决上面的这个问题,微软引进了PAC,引进PAC之后的kerberos流程变成:

1、用户向KDC发起AS_REQ,请求凭据是用户hash加密的时间戳,KDC使用用户hash进行解密,如果结果正确返回用krbtgt hash加密的TGT票据,TGT里面包含PAC,PAC包含用户的sid,用户所在的组

2、用户凭借TGT票据向KDC发起针对特定服务的TGS_REQ请求,KDC使用krbtgt hash进行解密,如果结果正确,就返回用服务hash加密的TGS票据。此时KDC会验证TGT中的PAC的签名,判断PAC是否被篡改,如果PAC完好,则重新构造新的PAC放在TGS票据中。

3、用户拿着TGS票据去请求服务,服务使用自己的hash解密TGS票据。如果解密正确,就拿着PAC去KDC那边询问用户有没有访问权限,KDC解密PAC。获取用户的sid,以及所在的组,再判断用户是否有访问服务的权限,有访问权限就允许用户访问。

有些服务并没有验证PAC这一步,这也是白银票据能成功的前提,因为就算拥有用户hash,可以制作TGS,也不能制作PAC,PAC当然也验证不成功,但是有些服务不去验证PAC,这是白银票据成功的前提

特别说明的是,PAC对于用户和服务全程都是不可见的。只有KDC能制作和查看PAC。

MS14-068

补丁编号是KB3011780,域里面最严重的漏洞之一,它允许任意用户提升到域管权限。

利用条件:小于2012R2的域控,且没有打KB3011780(高版本默认集成)

该漏洞最本质的地方在于KDC无法正确检查Kerberos票证请求随附的PAC中的有效签名。导致用户可以自己构造一张PAC。

签名原本的设计是要用到HMAC系列的checksum算法,也就是必须要有key的参与,我们没有krbtgt的hash以及服务的hash,就没有办法生成有效的签名。但是问题就出在,实现的时候允许所有的checksum算法都可以,包括MD5。那我们只需要把PAC 进行md5,就生成新的校验和。这也就意味着我们可以随意更改PAC的内容,之后再用md5生成一个服务检验和以及KDC校验和。

在利用时,主要思路为:
1、发起一个AS_REQ的请求,请求中的PA_PAC_REQUEST设置为include_pac=false,此时KDC返回的TGT票据是不含有PAC的
2、伪造一个PAC。sid为当前用户的sid。将管理员组的sid加进GroupId。并且该PAC不是填充到TGT中,而是填充到TGS_REQ中的enc-authorization-data中,并且使用subkey加密,而subkey则放到authorization。在KDC用session_key进行解密之后,然后再通过这个subkey解密在authorization-data中的pac。最后KDC把PAC中的User SID、Group SID取出来,重新使用进行签名,签名算法和密钥与设置inclue-pac=true时一模一样。将新产生的PAC加入到解密后的TGS中,再重新加密制作全新的TGS发送给Client

域用户(513)、域管理员(512)、架构管理员(518)、企业管理员(519)、组策略创建者所有者(520)

不知道为何把这样放置PAC之后KDC还是依然能够解密PAC,原因不详

3、用户拿到这个TGS就可以域管理员身份访问服务

工具利用:

1
2
3
4
5
6
7
8
# kekeo
kekeo.exe "exploit::ms14068 /domain:域名 /user:域用户名 /password:用户明文 /sid:域用户sid /ptt" exit

# impacket中的goldenPac.py,这个脚本是结合ms14-068加psexec
python goldenPac.py <域名>/<用户名>:<密码>@<域控ip> -dc-ip <域控ip> -target-ip <域控ip>

# msf ms14_068_kerberos_checksum
msf的这个模块也支持14068攻击利用
文章作者: Dar1in9
文章链接: http://dar1in9s.github.io/2023/05/01/内网渗透/kerberos协议/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Dar1in9's Blog