这里的话其实是在thm简单的了解和查看了一遍 然后在打靶机的时候又遇到了 所以就自己写一下 加深印象

参考文章

介绍

Kerberos 是一种网络认证协议, 其设计目标是通过密钥系统为 客户机 服务器 应用程序提供强大的认证服务。该认证过程的实现不依赖于主机操作系统的认证,无需基于主机地址的信任,不要求网络上所有主机的物理安全,并假定网络上传送的数据包可以被任意地读取、修改和插入数据。在以上情况下, Kerberos 作为一 种可信任的第三方认证服务,是通过传统的密码技术(如:共享密钥) 执行认证服务的

其实也是两大AD域身份验证协议之一 另一个是NTLM协议 (微软专用)

这个协议默认是88端口

参与对象

  1. KDC : KDC是负责Kerberos协议的主要服务。该服务在域控制器服务器上运行。它包含 Active Directory 环境中所有客户端和服务帐户的信息和密码哈希。这些密码哈希值在 Kerberos 协议期间用作共享密钥
    1. Authentication Service (AS) : 它是密钥分发中心中负责认证步骤的模块。该模块通过检查客户端是否在Active Directory域(Domain)、提供的密码是否正确等信息来对客户端进行身份验证
    2. Ticket Granting Service (TGS): 该模块为经过身份验证的客户端提供必要票证的创建、验证和管理
    3. KRBTGT : 它是提供密钥分发中心服务管理的用户帐户。该用户的密码哈希用于加密某些票证
  2. 客户端 : 发起认证以访问服务的对象, 可以时用户账号也可以是机器账号, 在 AD 中每个用户和计算机都有一个账号, 其中用户账号是使用用户名创建的, 而计算机账号是使用 计算机名+$ 表示的, 计算机账号和用户账号一样都有密码这些密码每30天重新生成一次
  3. 服务端 : 客户端想要访问的服务, 管理这些服务的用户、计算机对象也被称为服务账号
  4. Account Database : 存储所有客户端的白名单 , 只有存在于白名单的客户才能申请 TGT

总结

  • TGT

TGT的申请条件就是必须是域用户 并且申请的时候密码也必须正确

  • TGS

这个的话是通过TGT身份验证通过后 想要在访问什么服务的时候才会去申请来创建对应的票据

简单认证流程

img

AS_REQ & AS_REP

用户将 用户名&密码派生的密钥加密的时间戳 发送的密钥分发中心 (KDC), 该服务通常安装在负责在网络上创建 Kerberos 票证的域控制器上, 当验证通过后, KDC 将创建发回票证授予票证(TGT) , 这将允许用户请求额外的票证以访问特定的服务, 需要一张票才能获得更多的票可能听起来有点奇怪,但它允许用户在每次想要连接到服务时无需传递其凭据即可请求服务票。与TGT一起的还有一个 TGS_Session_KEY 被提供给用户,我们需要基于此来获取更多的内容

TGT 是使用 krbtgt 帐户的密码哈希加密的,因此用户无法访问其内容。同时加密的TGT包括 TGS_Session_Key 的副本作为其内容的一部分,并且 KDC 无需存储会话密钥,因为它可以在需要时通过解密 TGT 来恢复副本

img

  • Session_key是啥

image-20230915153036447

  • TGT中包含了啥

TGT票据中包含的是与用户相关的身份信息,例如用户名、颁发票据的时间戳、票据的有效期等。此外,TGT票据还包含了Session Key,该密钥用于后续的票据交换和加密通信。

TGS_REQ & TGS_REP

  • 现在用户手里有了 TGT 和 TGS_Session_Key , 现在我们需要去获取服务的票证

现在用户如果想要连接到网络上的服务(如共享、网站或数据库)时, 他们将使用他们的 TGT 向 KDC 请求票证授予服务(TGS) 。TGS 是只允许连接到为其创建的特定服务的票证。要请求 TGS,用户将发送使用 TGS_Session_Key 加密的用户名和时间戳 ,以及 TGT服务主体名称 (SPN) ,后者指示我们打算访问的服务和服务器名称。

因此,KDC 将向我们发送一个 TGS 以及一个 Service_Session_Key,我们需要用它来验证我们想要访问的服务

(这个TGS的话是使用服务拥有者自己的hash值来进行加密的 TGT的话是使用krbtgt的hash值来进行加密的)

TGS 使用从服务所有者哈希派生的密钥进行加密 。服务所有者是运行服务的用户或机器帐户。TGS 在其加密内容上包含 Service_Session_Key 的副本,以便服务所有者可以通过解密 TGS 来访问它。

img

AP_REQ& AP_REP

然后可以将 TGS 发送到所需的服务以进行身份验证并建立连接。该服务将使用其配置的帐户密码哈希来解密 TGS 并验证 Service_Session_Keyw

img

详细流程

(上面讲的只是简单的流程 没有具体分析传了啥 干了啥)

接下来的话几乎都是照搬了

AS_REQ & AS_REP

AS_REQ

这一阶段 ClientAuthentication Service (身份验证服务器) 发出请求, 发送以下数据:

  • 域名、用户名
  • KRBTGT 的 SPN (这是 KDC 的 SPN )
  • 使用 Client 加密的时间戳 : 也就是我们的请求凭据 PA-DATA

img

以下是对数据包的分析

img

凡是皆有例外, 对于 AS_REQ 还存在一种特殊的情况就是: 不存在 PA-ENC-TIMESTAMP字段,也就是不再发送使用用户哈希加密的时间戳, 相当于绕过了第一步校验 (就是不进行预身份验证了 这样子造成的危害就是域控的话就不会对其用户身份进行校验 就直接将TGT和Session key返回回来)

img

这张图片就是显示的是 不进行预身份验证

(PAC的话等下在后面会讲到)

AS_REP

img

KDC 中的 Authentication Service (身份验证服务器) 接收到 Client 发出的请求后, 到 Kerberos 认证数据库 根据用户查找是否存在对应的用户 (此时只会查找是否有相同用户名的用户,并不会判断身份的可靠性 )

  • 不存在用户名, 认证失败, 服务结束

  • 存在用户, 返回响应

    • 使用

      1
      Client 哈希

      加密一段内容进行返回 (注意这是 Client 密钥意味这 Client 端可以解密)

      • TGS_Session_key
      • 时间戳
      • TGT 的存活时间
    • TGT (票据授予票据) : 客户端需要使用TGT去KDC中的 TGS(票据授予中心)获取访问网络服务所需的 Ticket(服务授予票据),TGT中包含的内容有 User Name/IDTGS Name/IDIP、当前时间戳、TGT 的有效时间、TGS_Session_key。整个TGT使用 krbtgt Hash 加密,客户端是解密不了的,由于密钥从没有在网络中传输过,所以也不存在密钥被劫持破解的情况

在这一阶段 AS 获取到用户名之后, 会根据对应的 用户NTLM 值来解密数据信息, 并且验证时间戳,之后生成随机字符串TGS_Session_key,使用用户的 NTLM 哈希值加密 TGS_Session_key,使用krbtgt用户的 NTLM 哈希加密TGS_Session_key和客户端信息 (TGT),一起返回客户端

1
Send=user_NTML_Hash(Session Key)+krbtgt_NTML_Hash(Session Key+client_info1)[TGT]

现在我们自然要开始分析数据包: (这一步会发送账号所以自然会出现三种情况), 这三种情况返回的包不同, 所以我们可以基于此来进行编写工具

  • 用户名和密码正确
  • 用户名不正确
  • 用户名正确, 密码不正确

密码什么时候传的?

在我们的第一阶段 AS_REQ 的时候数据包中存在一个 pmdata 我们将使用用户哈希加密的时间戳放在了其中 ———时间戳(使用从其密码派生的密钥加密)

  1. 用户名密码正确

img

  1. 用户名不正确 (第一个包)

img

  1. 用户名正确 密码不正确 (就是时间戳不对)

img

TGS_REQ & TGS_REP

TGS_REQ

img

当我们的 Client 端收到 AS 发来的数据后, 会使用我们的客户端的 Hash 来解密一部分数据从而获得 TGS_Session_Key 然后开始发送, 发送内容如下

  • AS_REP 阶段返回的 TGT 原样发送
  • 服务主体名称: 指示我们要访问的那个服务或者服务器
  • 使用 TGS_Session_Key 加密 User Name时间戳

img

TGS_REP

img

TGS 收到用户发出的请求后, 开始了一系列操w作

  1. 先去检查是否存在对应的服务
  2. KDC 对 TGT 内容进行解密
    1. 使用 TGT 中 TGS_Session_Key 使用此来 TGS_REQ 阶段 Client 加密的数据
    2. TGT 中包含 Client 端的 User Name和我们发送的内容进行比较

一旦上述验证通过就可以进入下一步

  1. 将当前用户信息存储在 TGS Cache

  2. TGS_Session_Key加密的内容:

    1. Service Session Key
    2. TGS 有效时间
    3. User nonce : 防止重放攻击
  3. TGS : 使用

    对应服务的密码加密

    的内容:

    1. Service Session Key
    2. UserName/ID
    3. TGS 有效时间
    4. PAC

img

AP_REQ& AP_REP

AP_REQ

img

客户端收到 TGS 后, 会使用在 AS_REP 阶段获取的 TGS_Session_Key 来解密数据从中获取到 Service Session Key, 然后向服务端发送数据包. 内容为:

  1. 从 TGS_REP 阶段获取的 TGS 原样发送
  2. 使用Service Session Key加密的内容
    1. User Name/ID
    2. 时间戳

AP_REP

服务端接收到用户请求后就可以开始一些操作

  1. 使用服务端 Hash 解密 TGS
    1. 验证时间戳
    2. 获取 Service Session Key
  2. 使用 Service Session Key 来解密用户传输的 Autherticator, 并验证其中的 User Name/ID时间戳

验证完毕后, 服务器将会返回响应:

  • 将 Client 信息保存在 Service Cash
  • 使用 Service Session Key加密的内容: Service Name/ID``时间戳

Client

Client 接收到服务方传来的响应, 使用在 TGS_REP 阶段获取的 Service Session Key解密, 验证是否是我们请求的服务, 验证成功后将 Servre Ticket保存到 User Cash 中

PAC

PAC 是 kerberos服务票证的扩展,其中包含各种授权信息、附加凭据信息、配置文件和策略,例如用户所属的用户组、用户所具有的权限,由于在域中不同权限的用户能够访问的资源是不同的,因此微软设计PAC用来辨别用户身份和权限,当用户在Active Directory(AD)域中进行身份验证时,域控制器会将 PAC 信息添加到kerberos票证(TGT 中) , 经过一系列请求后用户访问服务, 此时服务验证 TGS 后, 如果无误就会拿着 PAC 去 KDC 那边验证用户是否有访问服务的权限

这里存在一个漏洞:

  • 如果不验证 PAC, 那么我们就可以制作 TGS 来访问所有服务, 这也是白银票据成功的前提

简略介绍

KDC 在 AS_REP 的 TGT 中增加了 Client 的 PAC , 其简单结构我们可以从下面这张图中看出, 从中我们可以看到在 PAC 的尾部其实是有两个签名的:

  • Server Signature :
  • KDC Signature :

img

现在我们在 AS_REP 阶段获取了 PAC, 为了可以将 PAC 发送到 Server 端, 微软选择了如下做法:

  • 在 TGS_REQ 阶段, 携带 PAC 的 TGT 被 TGS 服务接收后, 验证完 TGT 后就会将 PAC 解密出来, 并验证两个签名的有效性, 如果无误就认为 PAC 没有被篡改于是更换签名
    • Server Signature : 使用 Server B 的密码哈希生成签名
    • KDC Signature : 使用 Service Session Key加密
  • 将重新生成的 PAC 拷贝在 TGS 中并加密起来

img

PAC签名

PAC中包含两个数字签名:PAC_SERVER_CHECKSUM和 PAC_PRIVSVR_CHECKSUM

PAC_SERVER_CHECKSUM 是用服务密钥进行签名,而 PAC_PRIVSVR_CHECKSUM 使用KDC密钥进行签名,签名的原因有两个:

  1. 存在带有服务密匙的签名,以验证此 PAC服务 已由服务签名。
  2. 带有KDC密匙的签名是为了防止不受信任的服务用无效的PAC为自己伪造票据。

两个签名的类型分别为 PAC_SERVER_CHECKSUM 和 PAC_PRIVSVR_CHECKSUM 类型的

PAC_INFO_BUFFFER发送。在PAC数据用于访问控制之前,必须检验带有PAC_SERVER_CHECKSUM 的签名,因为这将验证客户端是否知道服务的密匙。而PAC_PRIVSVR_CHECKSUM 签名是可选的,默认不开启。它将验证PAC是否由KDC签发,而不是由KDC以外的具有访问服务密匙的第三方放入票据中。

KDC 验证 PAC

当服务端接收到 AP_REQ消息时,只能校验PAC_SERVER_CHECKSUM签名,并不能校验PAC_PRIVSVR_CHECKSUM 签名。

因为,如果要检验 PAC_PRIVSVR_CHECKSUM 签名,服务端还需要将客户端发来的ST签名中的PAC签名发回KDC进行校验。但是大部分服务默认没有开启KDC验证PAC这一步(需要目标服务主机配置为验证KDC PAC签名,默认未开启),因此服务端就无须将ST中的PAC签名发送到KDC校验了。

这也是白银票据攻击成功的前提,因为如果目标服务主机为需要校验PAC_PRIVSVR_CHECKSUM 签名,服务器会将这个PAC的数字签名的结果以KRB_VERIFY_PAC的消息通过RPC协议发送给KDC,KDC再将验证后这个PAC的结果以RPC返回码的形式发送回服务端,服务端根据返回的结果判断PAC的真实性与有效性。这样就算攻击者拥有服务密匙,制作ST票据,也无法伪造PAC_PRIVSVR_CHECKSUM签名,自然无法通过KDC签名校验了。

注意:在本地系统账户下的服务,无论如果配置都不会触发KDC签名验证,也就是说SMB、CIFS、HOST等服务,无论如何都不会触发KDC验证PAC签名。

为什么KDC默认不验证PAC签名?

如果执行KDC验证PAC,意味着有响应时间和带宽使用方面的成本。它需要占用带宽在应用服务器和KDC之间传输请求和响应,这可能导致大容量应用程序服务器中出现了一些性能问题。这样的环境中可能导致额外的网络延迟和大量流量。

PAC是微软的一个特性,所以启用了PAC的域中不支持其他操作系统的的服务器,制约了域配置的灵活性。