域渗透|Kerberos域认证机制剖析

域渗透|Kerberos域认证机制剖析

Kerberos域认证机制剖析

Kerberos概念

Kerberos是一种网络认证协议,其设计目标是通过密钥系统为Client / Server应用程序提供强大的认证服务。该认证过程的实现不依赖于主机操作系统的认证,无需基于主机地址的信任,不要求网络上所有主机的物理安全,并假定网络上传送的数据包可以被任意地读取、修改和插入数据。

在以上情况下, Kerberos作为一种可信任的第三方认证服务,是通过传统的密码技术(如:共享 密钥)执行认证服务的。

域认证所参与的角色

Kerberos的标志是三只狗头,狗头分别代表以下三个角色

    1. 访问服务的Client
    1. 提供服务的Server
    1. KDC(Key Distribution Center)密钥分发中心 kerberos 测试工具介绍

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

Kerberos认证协议

TGT(Ticket Granting Ticket)

由身份认证服务AS(Authentication Service)授予的票据,TGT用于身份认证,存储在内存,默认有效期为10小时,通过TGT能够获得票据(Ticket)TGT是一种 临时凭证 的存在,伪造的TGT又被称为 黄金票据

票据(Server Ticket/Ticket)

是网络对象互相访问的 凭证伪造的ST\Ticket又被称为 白银票据

KDC(Key Distribution Center)

负责管理票据、认证票据、分发票据,但是KDC不是一个独立的服务,它由以下服务组成:

  • AS(Authentication Service): 身份认证服务,为Client生成TGT(Ticket Granting Ticket)的服务。
  • TGS(Ticket Granting Service): 票据授予服务,为Client生成某个服务的Ticket的服务。

AD(Account Database)

一个类似于本机SAM的一个数据库,存储所有Client的白名单,只有存在于白名单的Client才能顺利申请到TGT

※补充:从物理层面看,AD与KDC均为域控制器(Domain Controller)。

域认证粗略流程

过程简述

①-②:Clientkerberos服务请求,希望获取访问Server的权限。 kerberos得到了这个消息,首先得判断Client是否是可信赖的, 也就是白名单黑名单的说法。

这就是AS(Authentication Service)服务完成的工作,通过在AD(Account Database)中存储黑名单和白名单来区分Client

成功后,AS(Authentication Service)返回TGT(Ticket Granting Ticket)Client

③-④:Client得到了TGT(Ticket Granting Ticket)后,继续向kerberos请求,希望获取访问 Server的权限。kerberos又得到了这个消息,这时候通过Client 消息中的TGT,判断出了Client拥有了这个权限,给了Client访问Server的权限Ticket

⑤-⑥:Client得到Ticket后,终于可以成功访问Server。这个Ticket只是 针对这个Server,其他Server需要向TGS(Ticket Granting Service)申请。

较详简述

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

  2. AS_REP: KDC使用Client hash进行解密,如果结果正确就返回用krbtgt hash加密的TGT票据,TGT里面包含PACPAC包含用户Clientsid用户Client所在的

  3. TGS_REQ: Client凭借TGT票据向KDC发起针对特定ServerTGS_REQ请求

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

  5. AP_REQ: Client拿着TGS票据(Ticket)去请求Server

  6. AP_REP: Server使用自己的hash解密TGS票据(Ticket)。如果解密正确,就拿着PACKDC那边问Client有没有访问权限,域控解密PAC。获取Clientsid,以及所在的,再根据该服务的ACL,判断Client是否有访问Server的权限。

域认证详细流程

AS_REQ & AS_REP

AS_REQ

1
2
3
4
5
6
7
8
1. pvno
kerberos 版本号
2. msg-type
类型,AS_REQ对应的就是KRB_AS_REQ(0x0a)
3. PA_DATA
主要是一些认证信息。一个列表,包含若干个认证消息用于认证,我们也可以Authenticator。每个认证消息有type和value。
4. REQ_BODY
kdc-options 一些flag 字段

AS_REP

1
2
3
4
5
6
7
8
9
10
1. msg-type
AS_REQ的响应body对应的就是KRB_AS_REP(0x0b)
2. crealm
域名
3. cname
用户名
4. ticket
这个ticket用于TGS_REQ的认证。是加密的,用户不可读取里面的内容。在AS_REQ请求里面是,是使用krbtgt的hash进行加密的,因此如果我们拥有krbtgt的hash就可以自己制作一个ticket,既黄金票据。详情见相关的安全问题>黄金票据.
5. enc_part
这部分是可以解密的,key是用户hash,解密后得到Encryptionkey,Encryptionkey里面最重要的字段是session key,作为下阶段的认证密钥。

TGS_REQ & TGS_REP

TGS_REQ

1
2
3
4
5
6
7
8
9
10
11
1. msg-type
类型,TGS_REQ对应的就是KRB_TGS_REQ(0x0c)
2. PA-DATA
正常的TGS_REQ的请求需要用到有
AP_REQ:这个是TGS_REQ必须携带的部分,这部分会携带AS_REP里面获取到的TGT票据,就放在这个结构体里面。KDC校验TGT票据,如果票据正确,就返回TGS票据。
PA_FOR_USER:类型是S4U2SELF,值是一个唯一的标识符,该标识符指示用户的身份。该唯一标识符由用户名和域名组成。S4U2proxy 必须扩展PA_FOR_USER结构,指定服务代表某个用户(图片里面是administrator)去请求针对服务自身的kerberos服务票据。
PA_PAC_OPTIONS:值是以下flag的组合Claims(0)、Branch Aware(1)、Forward to Full DC(2)、Resource-based Constrained Delegation (3)。微软的MS-SFU 2.2.5,S4U2proxy 必须扩展PA-PAC-OPTIONS结构。
如果是基于资源的约束委派,就需要指定Resource-based Constrained Delegation位。
3. REQ_BODY
sname:这个是要请求的服务,TGS_REP获得的ticket是用该服务用户的hash进行加密的。有个比较有意思的特性是,如果指定的服务是krbtgt,那么拿到的TGS票据是可以当做TGT票据用的。
AddtionTicket:附加票据,在S4U2proxy请求里面,既需要正常的TGT,也需要S4U2self阶段获取到的TGS,那么这个TGS就添加到AddtionTicket里面。

TGS_REP

1
2
3
4
5
6
1. msg-type
AS_REQ的响应body对应的就是KRB_TGS_REQ(0x0d)
2. ticket
这个ticket用于AP_REQ的认证。其中里面的enc_part是加密的,用户不可读取里面的内容。在AS_REQ请求里面是,是使用krbtgt的hash进行加密的,而在TGS_REQ里面是使用要请求的服务的hash加密的。因此如果我们拥有服务的hash就可以自己制作一个ticket,既白银票据。详情见相关的安全问题>白银票据.正因为是使用要请求的服务的hash加密的,所以我们可以通过爆破enc_part获得该服务的hash,详情见相关的安全问题>kerberoasting。
3. enc_part
注意,这个enc_part不是ticket里面的enc_part,部分是可以解密的,key是上一轮AS_REP里面返回的session_key,也就是导入凭据里面的 session_key,解密后得到encryptionkey,encryptionkey这个结构里面最重要的字段也是session_key(但是这个session_key 不同于上一轮里面的session_key),用来作为作为下阶段的认证密钥。

S4U2SELF

s4u2self的过程如下图所示(前提条件是服务已经有通过KDC验证的TGT)

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

S4U2PROXY

s4u2proxy的过程如下图所示

s4u2proxy 使得服务1可以使用来自用户的授权( 在S4U2SELF阶段获得),然后用该TGS(放在AddtionTicket里面)向KDC请求访问服务2的TGS,并且代表用户访问服务2,而且只能访问服务2。

委派

在Windows 2000 Server首次发布Active Directory时,Microsoft必须提供一种简单的机制来支持用户通过Kerberos向Web Server进行身份验证并需要代表该用户更新后端数据库服务器上的记录的方案。这通常称为“ Kerberos双跳问题”,并且要求进行委派,以便Web Server在修改数据库记录时模拟用户。

需要注意的一点是接受委派的用户只能是服务账户或者计算机用户

非约束委派

例子:

服务(如JACKSON-PC$) 被配置了非约束的委派,那么JACKSON-PC$可以接受任何用户的委派的去请求其他所有服务。在协议层面的实现就是,某个用户委托JACKSON-PC$去访问某个服务,那么这个用户会将 TGT(在TGS里面)发送到JACKSON-PC$并缓存到LSASS中,以方便以后使用。 然后JACKSON-PC$模拟用户去请求某个服务。

配置了非约束委派的用户的userAccountControl 属性有个FLAGTrustedForDelegation

关于userAccountControl 每一位对应的意义可以看Converting AD UserAccountControl Attribute Values,(我们在LDAP篇也会详细介绍),其中 TRUSTED_FOR_DELEGATION 对应是 0x80000 ,也就是 524288 。

约束委派

微软很早就意识到非约束委派并不是特别安全,在 Windows 2003上发布了”约束”委派。

其中包括一组 Kerberos 协议扩展,就是本文之前提到的两个扩展 S4U2SelfS4U2Proxy。配置它后,约束委派将限制指定服务器可以代表用户执行的服务。这需要SeEnableDelegation特权(该特权很敏感,通常仅授予域管理员)才能为服务配置域帐户,并且将帐户限制为单个域。

例子:

计算机用户(即JACKSON-PC$) 被配置了约束的委派,那么JACKSON-PC$可以接受任何用户的委派的去请求特定的服务。具体过程是收到用户的请求之后,首先代表用户获得针对服务自身的可转发的kerberos服务票据(S4U2SELF),拿着这个票据向KDC请求访问特定服务的可转发的TGS(S4U2PROXY),并且代表用户访问特定服务,而且只能访问该特定服务。

相较于非约束委派,约束委派最大的区别也就是配置的时候选择某个特定的服务,而不是所有服务。

配置了约束委派的用户的userAccountControl 属性有个FLAG位 TrustedToAuthForDelegation 。

关于userAccountControl 每一位对应的意义可以看Converting AD UserAccountControl Attribute Values,其中 TRUSTED_TO_AUTH_FOR_DELEGATION 对应是 0x1000000 ,也就是 16777216 。

基于资源的约束委派

为了配置受约束的委派,必须拥有SeEnableDelegation特权(该特权很敏感,通常仅授予域管理员)。为了使用户/资源更加独立,Windows Server 2012中引入了基于资源的约束委派。基于资源的约束委派允许资源配置受信任的帐户委派给他们。基于资源的约束委派将委派的控制权交给拥有被访问资源的管理员。

基于资源的约束委派只能在运行Windows Server 2012 R2和Windows Server 2012的域控制器上配置,但可以在混合模式林中应用。

这种约束委派的风格与传统约束委派非常相似,但配置相反。

传统约束委派在msDS-AllowedToDelegateTo属性中的帐户A上配置,并定义从AB的“传出”信任。

基于资源的约束委派在S-AllowedToActOnBehalfOfOtherIdentity属性中的帐户B上配置,并定义从AB的“传入”信任。

PAC

微软为了访问控制而引进的一个扩展PACPAC在历史上出现过的一个严重的,允许普通用户提升到域管的漏洞MS14068

引进PAC之后的kerberos流程

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

  1. 用户凭借TGTKDC发起针对特定服务的TGS_REQ请求,KDC使用krbtgt hash进行解密,如果结果正确,就返回用服务hash加密的ST\Ticket(这一步不管用户有没有访问服务的权限,只要TGT正确,就返回ST\Ticket这也是kerberoating能利用的原因:任何一个用户,只要hash正确,就可以请求域内任何一个服务的ST\Ticket,具体内容可以参考Windows内网协议学习Kerberos篇之TGSREQ& TGSREP)

  2. 用户拿着ST\Ticket去请求服务,服务使用自己的hash解密ST\Ticket。如果解密正确,就拿着PACKDC那边询问用户有没有访问权限,域控解密PAC。获取用户的sid用户所在的组,再判断用户是否有访问服务的权限,有访问权限就允许用户访问(有用户hash,可以制作ST\Ticket,但是不能制作PACPAC自然也验证不成功,但是有些服务不去验证PAC,这是白银票据成功的前提)。

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

相关的安全问题

AS_REQ & AS_REP

PTH\ PTK

连接配置的时候允许使用hash进行认证,不是只有账号密码才能认证。

由于在进行认证的时候,是使用用户hash加密时间戳,所以在使用密码进行登录的情况下,也是先把密码加密成hash后再进行认证。

因此在只有用户hash,没有明文密码的情况下也是可以进行认证的。

不管是rubeus还是impacket里面的相关脚本都是支持直接使用hash进行认证。

1
2
如果 hash 是 ntlm hash ,然后加密方式是 rc4 ,这种就算做是 pass the hash
如果 hash 是 aes key(使用sekurlsa::ekeys导出来) ,就算是 pass the key

在很多地方,不支持rc4加密方式的时候,使用pass the key不失为一种好方法。

用户名枚举

域内没有域账号的情况下进行用户名枚举
有域账号的情况的下可以直接通过LDAP查询(域机器提到System权限后,其机器账号也是域账号)

进行AS_REQ时,用户名存在但密码错误用户名不存在的相应包有不同,通过这个比较就可以写脚本改变cname的值进行用户名枚举(https://daiker.gitbook.io/windows-protocol/kerberos/1#2.-yong-hu-ming-mei-ju)。

Password Spraying(密码喷洒)

在已有用户名的时候,可以尝试爆破密码。

进行AS_REQ时,用户名存在且密码正确用户名存在但密码错误的相应包有不同。

实战中,都会使用“密码喷洒(Password Spraying)”的技术来进行测试和攻击。因为针对同一个用户的连续密码猜测会导致帐户被锁定,所以只有对所有用户同时指定唯一的密码去登录尝试,消除帐户被锁定的概率从而增加破解成功率。

AS-REPRoasting(用户明文口令爆破)

对于域用户,设置了选项Do not require Kerberos preauthentication(不要求Kerberos预身份验证)

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

黄金票据

AS确认Client端登录者用户身份,通过伪造的TGT,可以获取任意Kerberos的访问权限,由krbtgt NTLM Hash加密。

伪造条件

1
2
3
4
1、域名称
2、域的SID值
3、域的KRBTGT账号的HASH(意味着你已经有域控制器权限了)
4、伪造任意用户名,可以是任意的

Kerberos认证中,Client通过AS(Authentication Service)认证后,AS会给Client一个
Logon Session KeyTGT,而Logon Session Key并不会保存在KDC中,krbtgtNTLM Hash又是固定的(此账户一般不会改密码),所以只要得到krbtgtNTLM Hash,就可以伪造TGTLogon Session Key来进入下一步ClientTGS的交互。

有了金票后,就可以跳过AS验证,直接同KDC交互,不用验证账户和密码,所以也不用担心域管密码被修改。

TGS_REQ & TGS_REP

PTT(pass the ticket)

Kerbreos 除了第一步AS_ERQ是使用 时间戳 加密用户hash验证之外,其他的步骤的验证都是通过票据,这个票据可以是TGT(Ticket Granting Ticket)或者TGS票据(Server Ticket/Ticket)。因为票据里面的内容主要是session_keyticket(使用服务hash加密的,服务包括krbtgt),拿到票据之后,我们就可以用这个票据来作为下阶段的验证了。

kerberosting(服务hash爆破)

因为TGS_REP里面ticket里的enc_part(是ticket里面的enc_part,不是最外层的enc_part,最外层的enc_part是使用AS_REP里面的session_key加密的,这个session_key我们已经有了,没有意义),是使用要请求的服务的hash加密的,所以我们可以通过爆破获得服务的hash

这个问题存在的另外一个因素是因为用户向KDC发起TGS_REQ请求,不管用户对服务有没有访问权限,只要TGT正确,那么肯定会返回TGS

其实AS_REQ里面的服务就是krbtgt,也就是说这个同样用于爆破AS_REP里面的ticket部分的encpart得到krbtgt的hash,但网上没出现这种攻击方式是因为krbtgt的密码是随机生成的,我们也跑不出来.

白银票据

ClientServer发送服务请求,通过伪造的Ticket,只能访问指定的服务,如cifs、http、mssql等,由服务账号NTLM Hash加密。

伪造条件

1
2
3
4
5
6
1、域名称
2、域SID
3、目标服务器的FQDN(Fully Qualified Domain Name全限定域名,即同时带有主机名和域名的名称。)
4、可利用的服务(运行在目标服务器上的kerberos服务,该服务主体名称类型如cifs,http,mssql等)
5、服务账号的NTLM Hash(如果是域控制器,那就代表DC已经被拿下了)
6、需要伪造的用户名,可以是任意的

Kerberos认证中的第⑤-⑥步,Client带着TicketAuthenticator3Server上的某个服务进行请求,Server接收到Client的请求之后,通过自己的Master Key解密Ticket,从而获得Session Key。通过Session Key解密Authenticator3,进而验证对方的身份,验证成功就允许Client访问Server上的指定服务了。

所以我们只需要知道Server用户的Hash就可以伪造出一个Ticket且不会经过KDC,但是伪造的Ticket只对部分服务起作用(已经在TGTPAC里,通过SID的值限定了给Client授权的服务)。

非约束委派攻击

如果我们找到配置了 非约束的委派的账户,比如JACKSON-PC$,并且通过一定手段拿下该账户的权限,然后诱导域管访问该JACKSON-PC$,这个时候域管会将自己TGT发送到JACKSON-PC$并缓存到LSASS中,那我们就可以从LSASS中导出域管的TGT票据,然后通过PTT,从而拥有域管的权限。

约束委派攻击

如果我们找到配置了 约束委派的服务账号,比如JACKSON-PC$,并且通过一定手段拿下该账号所在的机子。我们就可以利用这个服务账号代表任意用户 (重点:服务代表用户获得针对服务自身kerberos票据这个过程,服务不需要用户凭据) 进行s4u2self获得一个可转发的票据,然后把获取到的票据用于s4u2proxy(作为AddtionTicket),从而获取一个可转发的TGS服务就可以代替任意用户访问另外一个服务(既被配置的约束委派的服务cifs/WIN-JQO4OSMOGK2.JMU.com)。

相较于非约束的委派,约束的委派不需要用户过来访问就可以代表该用户,但是只能访问特定的服务,不像非约束的委派哪个可以访问任意服务。

1
2
3
4
5
6
对于 HOST SPN,可以实现完全的远程接管。
对于 MSSQLSvc SPN,可以拿到 DBA 权限。
对于 CIFS SPN 可以实现完全的远程文件访问。
对于 HTTP SPN 则可能实现接管远程网络服务。
对于 LDAP 则可以执行 DCSync。
对于 HTTP 或 SQL 服务帐户,即使它们没有提升目标服务器上的管理员权限,也可能使用 Rotten Potato 进一步滥用,提权至 SYSTEM 的权限

基于资源的约束委派攻击

基于资源的约束委派具有传统的约束委派的所有安全问题,但是相较于传统的约束委派。基于资源的约束委派的利用又相对较为简单

主要体现为,普通的约束委派的配置需要SeEnableDelegation权限,而这个权限通常仅授予Domain Admins。因此我们对普通的约束委派的利用,往往在于寻找域内已有的约束委派,再利用

但是对于基于资源的约束委派,假如我们已经拥有服务账号1,那么只要具备用户2的LDAP权限,这样就可以配置服务1对服务2的约束委派(在服务账户2的用户属性上配置S-AllowedToActOnBehalfOfOtherIdentity1sid),服务1就可以控制服务2

PAC

MS14068

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

该漏洞最本质的地方在于Microsoft Windows Kerberos KDC无法正确检查Kerberos票证请求随附的特权属性证书(PAC)中的有效签名,这里面的签名就是上面提到的服务检验和KDC校验和。导致用户可以自己构造一张PAC。 签名原本的设计是要用到HMAC系列的checksum算法,也就是必须要有key的参与,我们没有krbtgt的hash以及服务的hash,就没有办法生成有效的签名,但是问题就出在,实现的时候允许所有的checksum算法都可以,包括MD5。那我们只需要把PAC进行md5,就生成新的校验和。这也就意味着我们可以随意更改PAC的内容,完了之后再用md5给他生成一个服务检验和以及KDC校验和。在MS14-068修补程序之后,Microsoft添加了一个附加的验证步骤,以确保校验和类型为KRB_CHECKSUM_HMAC_MD5

https://daiker.gitbook.io/windows-protocol/kerberos/3#0x03-xiang-guan-an-quan-wen-ti

参考文章

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

https://payloads.online/archivers/2018-11-30/1/

https://www.cnblogs.com/0x7e/p/13862453.html

https://www.jianshu.com/p/4936da524040

作者

Se7en

发布于

2021-10-20

更新于

2022-03-31

许可协议

评论