写在最前
如果你是信息安全爱好者,如果你想考一些证书来提升自己的能力,那么欢迎大家来我的 Discord 频道 Northern Bay。邀请链接在这里:
https://discord.gg/9XvvuFq9Wb
我会提供备考过程中尽可能多的帮助,并分享学习和实践过程中的资源和心得,大家一起进步,一起 NB~
背景
本来对于 Kerberos 的鉴权过程我不想写了。但是有很多朋友问我,然后我又想了下,由于 Kerberos 鉴权过程中涉及了挺多的概念,并且过程一来一去,使用不同的主体先加密,后解密,一不小心,就会迷失在这些操作当中。不管是 Offensive Security 的课程,还是网上绝大多数的资料,从语言的组织,图例的使用,都不是很好。直到我读到这一篇文章的时候,我觉得作者(Jake Karnes)非常善于使用图例和一些视觉上的区分方式,很好地解释了整个 Kerberos 鉴权的过程,以及 3 种不同的 Active Delegation。
原文是关于 Bronze Bit Attack,但是作者为了更好的说明攻击原理,把整个 Kerberos 鉴权过程以及 Active Directory Delegation 讲得非常详细。我会借用他文章中的图片,然后加以调整,说明。
如果读完这篇文章,大家对 Kerberos 的鉴权过程还有不清楚的地方,那么,就请多看几遍吧 😄
后续
这篇文章之后,近期的计划就是承接这篇文章的内容,写一下 Active Directory Delegation(主要关于 protocol transition 的效用),再写一下 Bronze Bit Attack 的原理和利用。当然,参考文献都是 Jake Karnes 的研究结果。然后,我会写一些关于 Active Directory 证书鉴权的文章,最后当然是如何利用配置不当的证书做提权和后渗透维持。
开始吧!跟着走。
给域做个类比
我们把整个域(Active Directory)想象成一个游乐园,域中的各个服务,就想象成游乐园中的游乐项目。用户访问域中的服务,就想象成游客去游玩一个游乐项目。
不过,这个游乐场有一个很大的特殊性,就是你进去之后,想要玩任何一个游乐项目,都要回到大门口,向检票员出示门票,然后才能享受这个游乐项目。
记住这个类比,很有用。
什么是 Kerberos
Kerberos 是一个协议,用来集中管理访问权限的协议。用户在 Kerberos 协议中,对想访问的服务,无需一次一次重复鉴权。所有鉴权,都由 Kerberos 统一管理,提升了用户体验,也增加了安全性。
Kerberos 最初由 MIT 开发,微软拿来改巴改巴,出了新的 RFC(RFC4120),自成了一派,延用至今。
这大致上就是 Kerberos 的作用和由来。
Kerberos Authentication
开始之前,需要知道 Domain Controller(域控)中保存了每个用户的 Secret Key(以下称:用户 Key),每个服务的 Secret Key(以下称:服务 Key),以及它自己的 Secret Key(以下称:KDC Key)。
Domain Controller
- 域控,Key Distribution Center(KDC),就像是游乐场大门的检票员,负责检查每个游客的门票,并根据校验结果分发各个游乐项目的使用权
Key Distribution Center(KDC)
- 保存了域中所有用户,所有服务,以及自身的 Secret Key;并负责分发各种门票(包括大门的,以及各个游乐项目的)
下图中,用户 Key(红色),服务 Key(绿色),KDC Key(灰色),都保存在域控的 KDC 中。这个图例中各个 Key 的颜色将会贯穿文章始终。
Secret Key
- Secret Key 即所有域中主体密码的哈希值(password hash)
我们剥个洋葱,一层一层深入下去。
洋葱第一层:域中用户通过 Kerberos 想要访问一个服务的过程
在域环境中,假设一个用户想通过 Kerberos 协议访问 Web 服务器(或任意服务),整个过程可以很简单地被分为三大步:
第一步,用户向 Domain Controller 索取 Ticket Granting Ticket(TGT) ,以便访问域中的服务;
第二步,用户使用 TGT,向 Domain Controller 索取服务的“门票”(TGS);
第三步,用户向特定服务出示 TGS,使用该服务;
TGT
- TGT 就像是游乐园的大门门票,只有有了这张门票,才有进一步享受游乐项目(域中的服务)的资格
TGS
- TGS 就像是单个游乐项目的入场券,只有拿着这个,才能游玩特定的游乐项目
就那么简单。
重要信息:
- 一个用户的 TGT,是非常重要的数据;如果你获得了一个用户的 TGT,那么意味着你可以代表这个用户,访问这个用户可以访问的任意服务;
- 再进一步,也就是说如果你获取了 Domain Admin 的 TGT,那么你就拿下了整个域;
洋葱第二层:解剖获取 Ticket Granting Ticket(TGT)的过程
域是一个游乐场,我们要进去,第一步必须问检票员拿到大门的门票。
获取大门门票的过程,就是向 KDC 获取 TGT 的过程,这个过程,被称为 Authentication Server Request(AS_REQ)。
Authentication Server Request(AS_REQ)
修改一下 Jake Karnes 的时序图。
步骤说明:
- 用户登录,密码经过哈希获得 用户 Key(红色);
- 使用 用户 Key(红色)加密当前时间戳;
- 向 KDC 发起 Authentication Server Request(AS_REQ),把加密的 时间戳 和 用户名 一起发送给 KDC;
- KDC 将通过 用户名,找到保存在域中的 用户 Key(红色);
- KDC 用找到的 用户 Key(红色),解密时间戳;
- 如果第 5 步解密成功,说明了该用户通过了 KDC 的 Key 验证,那么 KDC 会生成一个 随机的 logon session key(紫色);
- KDC 发送 Authentication Server Reply(AS_REP) 给用户,包含了 TGT 以及其他加密数据;
Timestamp 时间戳校验的作用
- 时间戳校验是防止第三方使用窃取的老旧时间戳来发起 replay attack;所以 KDC 必须保证每个鉴权请求都在其所允许的时间范围内,通常是 3-5 分钟;
- 因此有时候,如果你在对域控使用工具的时候,你的系统时间和域时间相差太大,一些命令就会执行失败,这也就是时间戳校验的结果;
Authentication Server Reply(AS_REP)解析
在 Authentication Server Request(AS_REQ) 的最后一步中,KDC 会将 TGT 等数据加密并发送给用户。
如下图。
拆解一下。
- 这是整个响应数据的 非加密 部分;cname 就是整个鉴权过程中的用户名;张三李四等等;
- 这个部分使用 用户 Key(红色) 加密;包含了:
- Authentication Server Request 过程中 KDC 生成的随机 logon session key(紫色);
- 一些元信息,如 Flags(该票据是否 forwardable,之后的文章中会讲到);sname,服务的名称,Authentication Server Request 请求的服务是 Ticket Granting Service(krbtgt);
- 这个部分,也就是 TGT,使用 KDC Key(灰色) 加密,是用户无法解密的;用户就是用这个 TGT 来进行后续的服务鉴权(类比成,出示这个门票,才可以购买特定游乐项目的入场券);
重要信息:
- 这里,用户在接到 KDC 的响应之后,就会用自己 用户 Key(红色),解密第二部分信息,取出 logon session key(紫色),和第三部分 TGT 一起,保存起来,供之后使用
- 此时,拥有 TGT 的用户,就是拿到了游乐园门票的游客,获得了进入游乐园大门(域)的资格
洋葱第三层:解剖获取 Ticket Granting Service(TGS)的过程
这里,用户可以凭借之前获取的 TGT,来获取服务的使用权限。
就像我们说的,这就是你向游乐园的检票员出示门票,然后获取相应游乐项目入场券的过程。这个过程,被称为 Ticket Granting Service Request(TGS_REQ)。
Ticket Granting Service Request(TGS_REQ)
修改一下 Jake Karnes 的时序图。
步骤说明:
- 同样的,用户需要 加密一个时间戳;不同的是,这次不是用用户 Key,而是用 Authentication Server Request(AS_REQ)过程中 KDC 生成的 logon session key(紫色) 来加密;
- 用户向 KDC 发起 Ticket Granting Service Request(TGS_REQ),发送 3 样东西:
- 加密的 时间戳;
- TGT;
- 以及 想要访问的目标服务名称;
- 由于 TGT 是用 KDC Key(灰色) 加密的,因此,KDC 会使用 KDC Key(灰色) 对 TGT 进行解密;
- 解密之后,KDC 获取封装在 TGT 中的 logon session key(紫色);
- KDC 使用该 logon session key(紫色),解密时间戳;
- 如果第 5 步解密成功,说明该用户的 TGT 有效(因为用户使用 logon session key(紫色) 加密的时间戳,可以用 TGT 中的 logon session key(紫色) 解密;换句话说,用户持有的 logon session key(紫色) 与 TGT 中的 logon session key(紫色) 一致),这时,KDC 会再生成一个随机的 service session key(黄色);
- KDC 发送 Ticket Granting Server Reply(TGS_REP) 给用户,包含了 Service Ticket(TGS),以及其他加密数据;
Ticket Granting Server Reply(TGS_REP)解析
在 Ticket Granting Service Request(TGS_REQ) 的最后一步中,KDC 会将 TGS 等数据加密并发送给用户。
如下图。
拆解一下。
- 这是整个响应数据的 非加密 部分;cname 就是整个服务权限请求过程中的用户名;张三李四等等;
- 这个部分使用 logon session key(紫色) 加密;包含了:
- Ticket Granting Service Request(TGS_REQ)过程中 KDC 生成的随机 service session key(黄色);
- 一些元信息,如 Flags(该票据是否 forwardable,之后的文章中会讲到);sname,服务的名称;
- 这个部分,也就是 TGS,使用 服务 Key(绿色) 加密,是用户无法解密的;用户就是用这个 TGS 来访问域中的目标服务(类比成,拿着这个入场券,去享受游乐项目);
- Privilege Attribute Certificate,包含了额外的用户元数据,如他们的用户组,他们的权限等;这个部分会有两个加密签名,一个是 服务 Key(绿色)加密的签名,一个是 KDC Key(灰色)加密的签名;
PAC
- PAC 中的两个签名用于防止第三方篡改 PAC 来提权;由于 PAC 包含了一个用户的权限信息,一旦篡改,那么普通用户就可以获得管理员权限;
- 签名就是用来校验 PAC 的一致性;
重要信息-1:
- 这里,用户在接到 KDC 的响应之后,就会用保存的 logon session key(紫色),解密第二部分信息,取出 service session key(黄色),和第三部分 TGS 一起,保存起来,供之后使用
- 此时,拥有 TGS 的用户,就是拿到了某一个特定游乐项目的入场券,可以去游玩了
重要信息-2:
- 可以看到上图中的第 2 部分,是用用户持有的 logon session key(紫色) 加密的,所以这个部分中的任何内容,都是用户可以篡改的;
- 综上,如果我们拿下了这个用户,就可以作为这个用户,发起 TGS 请求,然后任意篡改服务名称(Rubeus 的 /altservice 功能),来访问任意服务;
洋葱第四层:解剖获取用户访问服务的过程
此时,用户可以凭借之前获取的 TGS,来访问具体服务了。
就像我们说的,这就是你拿着单个游乐项目的入场券,进去high了。
再次借用 Jake Karnes 的时序图。
步骤说明:
- 用户使用 Ticket Granting Service Request(TGS_REQ) 过程中获取的 service session key(黄色) 加密当前时间戳;
- 用户向 目标服务 发起 Application Request(AP_REQ),发送 3 样东西:
- 加密的 时间戳;
- Service Ticket(TGS);
- 以及 自己的用户名;
- 目标服务使用 服务 Key(绿色) 解密 Service Ticket(TGS);
- 目标服务取出封装在 TGS 中的 service session key(黄色);
- 目标服务使用 service session key(黄色) 解密用户加密过的时间戳;并对其进行校验;
- 目标服务使用 服务 Key(绿色) 校验 PAC 文件的 服务签名;(可选)目标服务也可以选择将 PAC 文件 发送给 KDC,让其进一步校验 KDC 签名;
- 上述校验全部通过,用户就可以畅通无阻地使用该服务了;
至此,整个 Kerberos 的鉴权过程已经说完了。
总结
可以看出规律,下一步的加密,都是用上一步生成的 session key;而上一步生成的 session key,都会放在 KDC 的响应中传回给用户保存。
另外,也只需要记住,TGT 使用 KDC Key 加密(也就是 krbtgt 的 hash),TGS 使用 服务 Key(服务的 password hash) 来加密。
附录
类比对应关系
主体 | 类比 |
---|---|
域 | 游乐园 |
服务 | 游乐园的游乐项目 |
KDC | 游乐园大门检票员 |
TGT | 游乐园大门门票 |
TGS | 游乐园特定游乐项目的入场券 |
获取 TGT | 游乐园大门检票员检票的过程 |
获取 TGS | 向游乐园大门检票员出示大门门票,获取单个游乐项目入场券的过程 |
用户访问特定服务 | 用户游玩游乐园中的特定游乐项目 |
域主体名词一览
主体 | 备注 |
---|---|
Domain Controller | 域控,包含 KDC |
User | 域用户;如张三,李四 |
Service | 域中的服务;如 Web,数据库 |
域概念一览
概念 | 备注 |
---|---|
KDC Key(KDC Secret Key) | 域控的 password hash,也是 krbtgt 账户的 password hash |
用户 Key(User Secret Key) | 用户账户的 password hash |
服务 Key(Service Secret Key) | 服务账户的 password hash |
Timestamp | 时间戳,每个鉴权请求都必须发送当前时间戳做校验,防止 replay attack |
Session Key | 鉴权请求过程中 KDC 生成的随机数据,用来加密时间戳以请求 TGS 以及访问服务 |
AS_REQ | Authentication Service Request,用户向 KDC 发起登录鉴权的请求; |
AS_REP | Authentication Service Reply,KDC 校验用户成功之后,返回给用户 TGT |
TGS_REQ | Ticket Granting Service Request,用户向 KDC 发起的服务访问鉴权请求 |
TGS_REP | Ticket Granting Service Reply,KDC 校验用户 TGT 成功之后,返回给用户 TGS |
AP_REQ | Application Request,用户向目标服务发起的服务访问鉴权请求,鉴权成功,用户将可以使用该服务 |
PAC | Privilege Attribute Certificate,用户元数据,包含了额外的用户信息,如用户ID,用户全名,登录次数,用户权限等;PAC 文件带有服务和KDC的加密签名,用于校验 PAC,防止第三方篡改 PAC 来提权 |
参考链接
- https://www.netspi.com/blog/technical/network-penetration-testing/cve-2020-17049-kerberos-bronze-bit-theory/
- https://en.wikipedia.org/wiki/Kerberos_(protocol)
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/166d8064-c863-41e1-9c23-edaaa5f36962
- https://blog.netwrix.com/2023/01/10/what-is-the-kerberos-pac/
- https://www.secureauth.com/blog/kerberos-delegation-spns-and-more/