内网渗透学习(Kerberos篇)
Kerberos协议简介 & 认证过程
Kerberos 是一种由MIT提出的一种网络身份验证协议,用于域环境中,它是一种基于票据(Ticket)的认证方式。Kerberos 认证过程的实现不依赖于主机操作系统的认证,无需基于主机地址的信任,不要求网络上所有主机的物理安全,并假定网络上传送的数据包可以被任意的读取、修改和插入,在以上情况下,Kerberos 作为一种可信任的第三方认证服务,是通过传统的密码技术(共享密钥)执行认证服务的,并且可以有效地防止中间人攻击
在 Kerberos 协议中主要是有三个角色:
- 访问服务的 Client
- 提供服务的 Server
- 密钥分发中心 KDC(Key Distribution Center)
其中 KDC 服务默认会安装在一个域的域控中,而 Client 和 Server 为域内的用户或者是服务,如HTTP服务, SQL服务。在 Kerberos 中 Client 是否有权限访问 Server 端的服务由 KDC 发放的票据来决定

一些名词
Authentication Service(AS):身份验证服务器
Ticket Granting Service(TGS):票据授予服务器,用于 KDC 向 Client 和 Server 分发 Session Key(临时秘钥)
Ticket granting Cookie(TGC):存放用户身份认证凭证的 Cookie
Ticket granting Ticket(TGT):TGT 对象的 ID 就是 TGC 的值,在服务器端,通过 TGC 查询 TGT
Server Ticket(ST):ST 服务票据,由 TGS 服务发布
AS_REQ & AS_REP
首先当客户端试图访问域内某个服务时,客户端会向 KDC 中的 AS 发送一个请求,请求包含 Client Hash 加密的时间戳(用于预认证),Client Info,Server Info 等
AS 收到消息后会向 AD 请求查询是否有此用户,如果有则取出用户的 NTLM Hash ,并对请求中的时间戳进行解密,解密成功则证明客户端提供的密码正确,如果时间戳合适,此时预认证成功,然后 AS 生成一个临时密钥 Session Key,再次用 Client Hash 加密后作为响应包的一部分。此外还会产生一个 TGT(使用特定账户 krbtgt 的 NTLM Hash 对 Session Key,时间戳等进行的加密后的信息),然后将这两部分以及 PAC(用户的SID、用户所在的组等一些信息) 等信息回复给 Client
sequenceDiagram
participant Client
participant AS as AS (KDC)
participant AD
Client->>AS: 1. AS_REQ
Note over Client,AS: Client Hash(Timestamp)<br/>Client Info<br/>Server Info
AS->>AD: 判断用户是否存在
AD-->>AS: 返回用户信息 / NTLM Hash
Note over AS: 预认证:<br/>用Client对应的 NTLM Hash 解密<br/>判断时间是否有效
Note over AS: 生成临时密钥 Session Key,并用 Client Hash 加密
Note over AS: 构造 TGT:并用 krbtgt 用户的 Hash 加密信息
AS-->>Client: 2. AS_REP
Note over AS,Client: Client Hash(Session Key)<br/>TGT:KDC Hash(Session Key, Client Info,End Time)<br/>PAC(SID/组信息)
Note over Client: Session Key(解密并缓存到本地)<br/>TGT(无法解密)
这一阶段的目标是:让客户端证明自己的身份,并拿到一个用于后续通信的 TGT(Ticket Granting Ticket) 票据
TGS_REQ & TGS_REP
第一阶段结束后,客户端已经有了两样东西:TGT 和 AS 产生的 Session Key
然后 Client 向 KDC 发起针对特定服务的请求,将 TGT 和 Session Key(AS) 加密的 Client Info,Timestamp 和一些其他信息一起发给 KDC 的 TGS
TGS 收到 TGS_REQ 之后,用 krbtgt Hash 值对 TGT 凭据进行解密,得到 Session Key(AS),Client Info,End Time 等信息,然后用 Session Key(AS) 继续解密,得到时间戳,如果时间相差不多则用 Session Key(AS) 对 Server Session Key(TGS产生) 进行加密作为第一部分,用 Server Hash 对 Server Session Key(TGS产生)、Client Info、End Time 进行加密作为第二部分,两部分构成了 TGS 票据发给 Client(不管用户有没有访问服务的权限,只要TGT正确,就返回TGS票据)
这一阶段的目标是:客户端拿着第一阶段得到的 TGT,去申请某个具体服务的访问票据 Service Ticket
AP_REQ & AP_REP
和上一步类似,第二阶段结束后,客户端已经有:Ticket 和 TGS 产生的 Server Session Key
然后用 Server Session Key(TGS) 加密 Timestamp 和 Client Info 加上 Ticket 一起发送给 Server
Server 收到 AP_REP 之后用 Server Hash 对 Ticket 进行解密,得到 Server Session Key(TGS),然后用 Server Session Key(TGS) 解密,得到 Timestamp,再次进行比对,在允许时间内则进行下一步。Server 拿着 PAC 向 KDC 发起请求,域控解密 PAC,得到 Client 的 SID 以及所在的组等信息后返回给 Server,Server 将 Client 的权限与 ACL 进行比对,如果 Client 有访问权限,则返回 AP_REP 并与 Client 建立通信
Kerberos相关利用
PAC与MS14-068
PAC(Privilege Attribute Certificate) 在上面的 AS_REQ & AS_REP 这一步中有提到过。在 AS_REP 中,KDC 返回的 TGT 票据中包含了 PAC,它是用来验证 Client 的访问权限的,因为原始的 Kerberos 认证过程有一个很大的问题,那就是 TGS_REP 这一步,无论用户是否拥有对应服务的访问权限,只要验证用户身份通过都会返回 TGS 票据,这导致后续过程里用户可以直接拿着 TGS 票据访问任何服务
此外 PAC 对于用户和服务全程都是不可见的,只有 KDC 能制作和查看 PAC,这也确保了 PAC 的安全性。但是在有些服务中并没有验证 PAC 这一步,所以白银票据能利用成功
MS14-068
微软在实现的过程中,允许任意签名算法,只要客户端指定任意签名算法,KDC 服务器就会使用指定的算法进行签名验证。这导致它允许经过身份验证的用户在其获得的票证 TGT 中插入任意的 PAC。普通用户可以通过呈现具有改变了 PAC 的 TGT 来伪造票据获得管理员权限
未打3011780补丁的机子都能利用,下面用 impacket 中的 goldenPac.py 演示利用
goldenPac 是 MS14-068 与 psexec 结合的一个产物,运行后会产生一个 shell
1 | |
黄金票据(Golden Ticket)
在上述的 AS_REQ & AS_REP中,用户使用自身 Hash 加密时间戳发送给 KDC,KDC 验证成功后返回用 krbtgt Hash 加密的 TGT 票据。如果我们有 krbtgt 的 Hash,就可以自己给自己签发任意用户的 TGT 票据,跳过 AS 验证
利用条件
- 域名称
- 域 SID
- 域的 krbtgt 账户的 NTLM Hash
- 需要伪造的域管理员用户名
1 | |

1 | |
方式一:
在靶机上生成黄金票据后直接ptt
1 | |

使用dir \\aa.xxx.com\c$\来验证(aa是域控)(后面的都可以用这种方法来验证,包括白银票据,就不重复放图了)

方式二:
生成票据后保存到文件中,然后手动导入
1 | |

白银票据(Silver Ticket)
白银票据是出现在 TGS_REQ & TGS_REP 过程中的。在 TGS_REP 中,不管 Client 是否有权限访问特殊服务,只要 Client 发送的 TGT 票据是正确的,那么就会返回服务 Hash 加密的 TGS 票据。如果我们有了服务 Hash,就可以签发 TGS 票据,与黄金票据相比,白银票据只能访问特定服务,并且伪造的白银票据没有带有有效 KDC 签名的 PAC。如果将目标主机配置为验证 KDC PAC 签名,则白银票据将不起作用
利用条件
- 域名
- 域 SID
- 目标服务器的 FQDN(域名全称)
- 可利用的 Kerberos 服务,例如 cifs
- 服务账号的 NTLM Hash
- 要伪造的用户名(用于构造 PAC,任意用户名应该都可以,检查 PAC 的服务不多)
1 | |

生成票据并注入
1 | |

黄金票据与白银票据的区别
访问权限
- 黄金票据伪造 TGT,可以获取任何 Kerberos 服务权限
- 白银票据伪造 TGS,只能访问指定的服务
加密方式
- 黄金票据用 krbtgt 的 NTLM Hash 加密
- 白银票据用 Server 的 NTLM Hash 加密
认证流程
- 黄金票据的利用过程需要访问域控
- 白银票据的利用过程需不需要访问域控
AS_REP Roast
AS_REQ & AS_REP 认证的过程是 Kerberos 身份认证的第一步,只要用户提供的票据正确,服务就会返回 Client Hash 加密的 TGT 票据。而如果域用户设置了选项”Do not require Kerberos Preauthentication”(该选项默认关闭)关闭了预身份验证后去请求票据,此时域控会不作任何验证便将 TGT 票据和加密的 Session Key 等信息返回,因此攻击者就可以对获取到的信息进行离线破解,如果爆破成功就能得到该指定用户的明文密码,这种攻击方式被称作 AS_REP Roasting

几种利用方式
仅查找用户:利用 PowerSploit 的 PowerView.ps1 查找可利用的账户
1 | |

注意:有时候在不同的账户不同权限不同的登录方式下,工具也可能会出现判断错误或异常的情况
方法一:利用 Rubeus 将开启了无需预认证的用户的 Hash 值导出
1 | |

方法二:利用 Impacket 中的 GetNPUsers.py 来导出 Hash
1 | |
得到 Hash(这种类型的 Hash 无法进行 PTH)
1 | |
使用 hashcat 或者 john 爆破
1 | |


Kerberoasting和SPN
AS-REP Roasting 和 Kerberoasting 都是针对 Kerberos 认证机制 的离线口令破解攻击,但它们攻击的对象、前提条件和拿到的票据不同
和上面的 AS_REP Roast 不一样,Kerberoasting 发生在 TGS_REQ & TGS_REP 阶段。只要用户提供的票据正确,服务就会返回自身 Hash 加密的 TGS 票据,那么如果我们有一个域用户,就可以申请服务的 TGS 票据,票据的一部分会用服务账户的密钥加密,因此如果服务账户密码弱,就可能被本地爆破服务 Hash 得到服务密码,前提是服务账户注册了 SPN
SPN简介
在域中,服务通过 SPN(ServicePrincipal Names) 来作为唯一标识,每个使用 Kerberos 的服务都需要一个 SPN
SPN 分为两种,一种注册在 AD 上机器帐户(Computers)下,另一种注册在域用户帐户(Users)下
- 当一个服务的权限为 Local System 或 Network Service,则 SPN 注册在机器帐户(Computers)下
- 当一个服务的权限为一个域用户,则 SPN 注册在域用户帐户(Users)下
SPN格式与查询
1 | |
比如:手动注册一个名为 MSSQLSvc 的 SPN,将他分配给 dd 这个域管账户
1 | |
查询已经注册的 SPN
1 | |

CN=Users 的是域账户注册的 SPN,CN=Computers 是机器账户。我们应该选择域用户进行利用,因为机器用户的口令无法远程链接
Kerberoasting利用
域内的任意主机都可以查询 SPN,任何一个域用户都可以申请 TGS 票据
使用 PowerSploit 的 PowerView.ps1 查找可利用的 SPN
1 | |
或者使用 kerberoast 的 GetUserSPNs 查找
1 | |

根据扫描出的结果使用微软提供的类 KerberosRequestorSecurityToken 发起 kerberos 请求,申请票据
1 | |
Kerberos 协议中请求的票据会保存在内存中,可以通过 klist 命令查看当前会话存储的 kerberos 票据

然后可以使用 mimikatz 导出TGS
1 | |
或者用更简单的方式:直接用 Rubeus 导出 Hash 后用 Hashcat 跑就行,注意类型是 13100
1 | |
委派
Kerberos 的委派(Delegation),简单说就是:允许一个服务代表用户去访问另一个服务
比如用户访问一个 Web 应用,Web 应用后端还需要去访问数据库、文件服务器或 API。Kerberos 委派让 Web 应用可以 “以这个用户的身份” 继续访问后端资源,而不是只能用 Web 服务自己的身份
此外接受委派的用户只能是服务账户或者计算机用户
非约束委派
设置后服务被允许代表用户访问任意服务

假设我们有一台域内的可控主机 zz,并配置了非约束委派,当域控或者其他主机通过 Kerberos 协议访问我们的主机 zz 的时候,就会在内存留下 TGT 票据,我们可以通过 TGT 票据来访问该主机可以访问的任意服务
查找非约束委派
AdFind
1 | |

利用非约束委派
在 DC 上通过 WinRM 访问主机 zz(Windows Server 2012及以上默认是开启WinRM服务的,Windows Server 2008 R2需要 winrm quickconfig -q 来启动WinRM服务)
1 | |

此时主机 zz 上已经缓存了从 DC 登录过来的域管的 Ticket,使用 mimikatz 导出
1 | |

注入内存后测试
1 | |

在实际利用中我们需要诱导DC或者高权限用户来连接
非约束委派+Spooler打印机服务
上一小节中的非约束委派需要域控主动连接,所以有时比较被动和鸡肋。但是 SpoolSample 可以利用 Spooler 打印机服务来强制指定主机进行连接
利用条件是需要以域用户运行 SpoolSample,需要开启 Print Spooler 服务,该服务默认自启动
使用 SpoolSample.exe 程序,让 DC 强制访问和认证 (我的环境中AA是域控,ZZ是可控的非约束委派主机)
1 | |
同时使用 Rubeus 监听来自 DC 的 4624 登录日志(注意筛选条件)
1 | |

使用 Rubeus 导入 base64 格式的 Ticket
1 | |

然后就可以利用 mimikatz 了
1 | |

得到 krbtgt 用户的 Hash 之后可以生成一张 administrator 的黄金票据
1 | |
约束委派
服务只能代表用户访问指定的服务
由于非约束委派的不安全性,微软在 windows server 2003 中引入了约束委派,对 Kerberos 协议进行了拓展,引入了 S4U,其中 S4U 支持两个子协议:Service for User to Self(S4U2Self) 和 Service for User to Proxy(S4U2proxy),这两个扩展都允许服务代表用户从 KDC 请求票据。约束委派就是限制了 S4U2proxy 扩展的范围
1 | |
利用
我的测试环境: aa.xxx.com 为域控,zz.xxx.com 为域内主机
先配置约束委派环境。新建一个 sql 用户,并且注册 SPN 表示其为服务用户
1 | |
同时配置上 dc 的 cifs 可以被 sql 用户所委派。需要注意的是使用任何身份验证协议
在配置约束性委派时有两种模式,其核心区在于是否允许协议转换,具体如下:
- Use Kerberos only,仅使用 Kerberos:
用户必须先通过 Kerberos 访问服务 A,服务 A 需要拿到用户访问自身的、可转发的服务票据,之后才能通过 S4U2Proxy 向 KDC 申请访问被允许委派的后端服务 B 的票据。
这种模式不能凭服务 A 的账号权限直接通过 S4U2Self 伪造任意用户完成完整委派。- Use any authentication protocol,使用任何身份验证协议:
允许协议转换。即使用户没有先通过 Kerberos 访问服务 A,服务 A 也可以通过 S4U2Self 代表某个用户向 KDC 申请“该用户访问服务 A 自身”的票据,再通过 S4U2Proxy 将其转换为访问指定后端服务 B 的票据。
因此,如果攻击者掌握了服务 A 账号的凭据,并且该账号被配置了到目标 SPN 的约束委派,就可以伪造被允许委派的用户去访问目标服务。

查找约束委派
1 | |
约束委派的利用条件是需要知道服务账户的密码或 Hash,因为约束性委派在向 KDC 申请可转发 TGS 时,需要提供可转发的 TGT(这里需要自身的 Hash)。所以只要控制配置了约束性委派服务的机器,并获得了它的密码或 Hash,就可以劫持这台主机的 kerberos 请求过程,最终获得任意用户权限的 Ticket
方法一:使用 kekeo 和 mimikatz
1 | |

最后通过 mimikatz 使用 cifs 的 TGS 票据进行 ptt 即可
方法二:使用 Rubeus 和 mimikatz
1 | |
