Kerberos学习记录
前言
最近在学习域渗透,整理了一下大佬的内容,巩固一下Kerberos基础。
Kerberos 简介
Kerberos 是一种由 MIT(麻省理工大学)提出的一种网络身份验证协议。它旨在通过使用密钥加密技术为客户端/服务器应用程序提供强身份验证。
Kerberos协议框架
Kerberos协议三个主要角色:
- 访问服务的Client
- 提供服务的Sever
- KDC(Key Distribution Center) 密钥分发中心
由上图中可以看到 KDC 又分为两个部分:
如果把 Kerberos 中的票据类比为一张火车票,那么 Client 端就是乘客,Server 端就是火车,而 KDC 就是就是车站的认证系统。如果 Client 端的票据是合法的(由你本人身份证购买并由你本人持有)同时有访问 Server 端服务的权限(车票对应车次正确)那么你才能上车。当然和火车票不一样的是 Kerberos 中有存在两张票,而火车票从头到尾只有一张。
Authentication Server:AS 的作用就是验证 Client 端的身份(确定你是身份证上的本人),验证通过就会给一张 TGT(Ticket Granting Ticket)票给 Client。
Ticket Granting Server:TGS 的作用是通过 AS 发送给 Client 的票(TGT)换取访问 Server 端的票(上车的票 ST)。ST(ServiceTicket)也有资料称为 TGS Ticket,为了和 TGS 区分,在这里就用 ST 来说明。
KDC 服务框架中包含一个 KRBTGT 账户,它是在创建域时系统自动创建的一个账号,你可以暂时理解为他就是一个无法登陆的账号,在发放票据时会使用到它的密码 HASH 值。
这里也有一个很好的故事
某公司遭到竞争对手的渗透,大量公司员工账号被盗,公司领导瑟瑟发抖,因为现在不知道聊天窗对面是自己的员工还是竞争对手,在这种情况下怎么来保证员工和老板间的对话是安全并且互相可信的呢?
这时候就引入了一个第三者,HR,由于公司施行工资保密制度,员工之间不知道彼此工资的具体数字,但是HR知道全公司员工的工资数字,现在假定每个员工的工资都是不同的,我们用员工,老板,和HR来完成一个安全可信的加密机制,(假定HR是可信任的)员工,老板和HR便是Kerberos认证中的三个角色。
那么继续说,公司目前处在这样一个人与人之间毫无信任可言的情况下,还是要继续运转
某天,员工张二狗需要从老板大黄那里取得一份公司机密信息,但是如果二狗直接给老板发消息索要信息,那老板肯定不会给他,因为公司聊天工具里的人现在都是不可信任的,二狗不知道网线那边是不是真的老板,老板也不知道给自己发消息的是不是真的二狗,这时候就尴尬了
然后这时,聪明的老王出现了,老王是个国外读了10年本科的密码学砖家,他就给公司提出来一套流程,鉴于目前大家都没有办法确定某个人就是某个人,那么我们来用密码学的手段确定彼此的身份吧
这个流程是什么呢,如果二狗想给老板发消息,就要先通过HR来确定二狗就是二狗,怎么确定呢,二狗知道自己的工资,HR也知道二狗的工资,那么二狗就先给HR发个消息,我要找老板谈话,帮我弄个身份鉴定证书吧,但是二狗不能直接找HR要这个鉴定证书,因为二狗要先证明二狗就是二狗本人
于是二狗先给HR发了个消息,我是二狗,我要证明我就是二狗!
HR收到了二狗的消息,然后从公司数据库中一查,果然有二狗这个人,但是即使有这个人,又怎么确定二狗就是二狗本人呢,HR就用二狗的工资作为加密密钥,对一串非常复杂的数字(12345)进行加密作为消息A,然后又把这个数字12345和当前跟二狗聊天窗口的截图还有聊天的时间记到一个文件中,再用自己的工资对这个文件进行加密作为消息B
之后HR把用二狗工资加密的消息A和用自己工资加密的消息B一起发送给二狗,为什么要这样做呢,二狗如果能成功解密消息A,就能得到12345,因为只有真正的二狗知道自己的工资,假二狗不知道,消息B又是用来做什么的呢,我们继续看
二狗发送完消息之后,盯着聊天窗,然后钉,钉,响了两声,HR发来了两串东西,二狗看不懂,但是二狗想起来之前老王提出来的认证流程,先用自己的工资解密了第一个消息,得到了那串数字12345,然后用这串12345把跟HR聊天窗口的截图和时间放在一起进行了加密,作为消息D,那么消息C是什么呢,消息C就是HR发来的第二个消息,消息B,不过这次消息C中还要多一个东西,就是老板的名字大黄,大黄和消息B合在一起就组成了消息C
为什么呢,因为二狗这次发送的消息C和D就是为了证明他就是二狗本人,二狗自然确定自己就是真二狗,那么自然也要把老板的名字加到消息中,因为他要HR给他用来跟老板对话的身份鉴定证书,如果不加上老板的名字,HR即便确定了二狗是二狗,也不知道二狗要跟谁对话
现在消息C(消息B和老板的名字大黄)和消息D(二狗用12345加密的聊天窗口截图和聊天时间)就发到了HR那里
HR收到了消息C和D,得到了三个东西,原来用自己工资加密的消息B,老板的名字,和之前自己随便想出来的12345加密的消息D
这里就来到了第一个关键点,HR怎么通过这几个东西来确定二狗就是二狗呢,HR首先用自己的工资解密了消息C,得到了之前的聊天窗截图和聊天时间,还有自己之前随便想出来的12345,然后用这个12345来解密消息D,又得到了二狗对他们两个的聊天窗的截图和聊天时间,通过对比这两个聊天窗截图和时间是否都匹配,HR就确定了这个二狗是真的二狗(假二狗不知道真二狗的工资,所以就无法解密得到12345,也就没法用12345加密消息D,HR自然也没办法解密了),并且就是之前跟自己聊天的那个二狗(因为之前发过去的用自己工资加密的消息B原封不动的发回来了,而这个消息B除了自己谁都无法解密修改)
这里有人要问了,那HR直接用自己想出来的12345解密消息D不是也可以确定二狗就是真二狗吗,这个怎么解释呢,这个公司有一百万个员工,每个员工时不时都想跟老板说说话,而HR脑子存储量不够大,记不住12345这么复杂的数字,更何况是一百万个12345,那脑子不得爆炸了,所以把12345用自己的密钥加密发过去,再收回来用自己的密钥解密取出来,这样就不用记了
现在HR确定了二狗就是二狗,那么看看二狗想跟谁聊天吧,消息C中写的是老板大黄的名字,HR就从公司数据库中查,老板大黄:工资4块3毛1角
然后HR又用老板的工资,加密了和二狗聊天窗口的截图,聊天时间和另一串非常复杂的数字45678 作为消息E(也就是鉴定证书),和用从消息C中找到12345加密了新的复杂数字45678作为消息F
又回到二狗这里,二狗收到这两个消息,用12345解密了第二个消息F,得到了45678,然后用45678加密了自己和HR的聊天窗截图和聊天时间作为消息G,之后把消息E和消息G发给老板,是不是和之前很像
这时老板收到了二狗的消息,老板先用自己的工资解密了消息E(HR用老板工资加密的截图,聊天时间还有45678),得到了45678,然后用这串复杂的数字成功解密了消息G,得到二狗的截图和聊天时间,再对比这两个聊天截图和聊天时间是不是一样的,一样的话老板才能确定二狗是真二狗,经过HR权威认定的二狗,可以充满信任的聊天了,这里其实也有对老板身份的鉴别,因为假老板不会知道真老板的工资,自然也就没有办法解密消息E
至此整个认证流程基本结束,我们将其中的几个关键信息提取出来,换成正常含义下对应的词语
- 二狗 Client
- HR KDC
- 老板大黄 Service/Server
- 二狗的工资 Client NTLM Hash
- HR的工资 krbtgt NTLM Hash
- 老板的工资 Service/Server NTLM Hash
- HR工资加密的截图,时间和12345 TGT 黄金票据
- 老板工资加密的截图,时间和45678 TGS 白银票据
- 12345 Client/TGS Sessionkey
- 45678 Client/Service Sessionkey
- 聊天窗截图 Client ID
- 聊天时间 Timestamp 时间戳
Kerberos认证流程
当 Client 想要访问 Server 上的某个服务时,需要先向 AS 证明自己的身份,然后通过 AS 发放的 TGT 向 Server 发起认证请求,这个过程分为三块:
- The Authentication Service Exchange:Client 与 AS 的交互;
- The Ticket-Granting Service (TGS) Exchange:Client 与 TGS 的交互;
- The Client/Server Authentication Exchange:Client 与 Server 的交互。
The Authentication Service Exchange
Client->AS:也就是Client向AS发送认证的内容
Client先向KDC的认证服务器AS发送Authentor1,其中内容通过Client密码的Hash加密的时间戳、ClientID、网络地址、加密类型等其他内容
AS->Client :AS回复Client的认证内容
AS发送 Client 密码加密的 sessionkey-as 和票据 TGT(KRBTGT HASH 加密的 sessionkey-as 和 TimeStamp)
在 KDC 中存储了域中所有用户的密码 HASH,当 AS 接收到 Client 的请求之后会根据 KDC 中存储的密码来解密,解密成功并且验证信息。验证成功后返回给 Client 由 Client 密码 HASH 加密的 sessionkey-as 和 TGT(由 KRBTGT HASH 加密的 sessionkey-as 和 TimeStamp 等信息)。
TheTicket-Granting Service (TGS) Exchange
Client ->TGS 请求发送 Authenticator2 (sessionkey-as 加密 TimeStamp) 和票据 TGT(KRBTGT HASH 加密的 sessionkey-as 和 TimeStamp)
Client 接收到了加密后的 Sessionkey-as 和 TGT 之后,用自身密码解密得到 Sessionkey-as,TGT 是由 KDC 密码加密,Client 无法解密。这时 Client 再用 Sessionkey-as 加密 TimeStamp 和 TGT 一起发送给 KDC 中的 TGS(TicketGranting Server)票据授权服务器换取能够访问 Server 的票据。
TheClient/Server Authentication Exchange
KRB_AP_REQ
Client ->Server 发送 Authenticator3(sessionkey-tgs 加密 TimeStamp) 和票据 ST(Server 密码 HASH 加密 sessionkey-tgs)
Client 收到 sessionkey-as 加密的 sessionkey-tgs 和 Server 密码 HASH 加密的 sessionkey-tgs 之后用 sessionkey-as 解密得到 sessionkey-tgs,然后把 sessionkey-tgs 加密的 TimeStamp 和 ST 一起发送给 Server。
KRB_AP_REP
Server-> Client
server 通过自己的密码解密 ST,得到 sessionkey-tgs, 再用 sessionkey-tgs 解密 Authenticator3 得到 TimeStamp,验证正确返回验证成功。
Kerberos协议中的SPN
关于SPN
服务主体名称(SPN)是Kerberos客户端用于唯一标识给特定Kerberos目标计算机的服务实例名称。
服务主体名称是服务实例(有点类似服务,例如HTTP、MSSQL)的唯一标识符。Kerberos 身份验证使用 SPN 将服务实例与服务登录帐户相关联。因此SPN扫描可以通过域控执行服务发现。
SPN基础配置
详细可以查看微软官方手册
https://docs.microsoft.com/zh-cn/windows-server/networking/sdn/security/kerberos-with-spn
SPN格式
<serviceclass>/<host>:<port>/<service name> |
SPN注册
Setspn -S http/<computername>.<domainname> <domain-user-account> |
查询已经注册的SPN |
一般情况下基于主机的服务会省略后面两个组件,格式为
/ ,如:
HTTP/test.test.com
特别针对如果服务使用非默认端口需要加上特定端口和服务名
SPN利用
SPN扫描
在查询SPN的时候,会向域控制器发起LDAP查询,这是正常Kerberos票据行为的一部分,所以这个操作很难被检测出来。换句话说我们的SPN扫描和SPN查询,实际上就是查询LDAP中存储的内容,在域控中默认安装有ADSI编辑器,它是LDAP的编辑器,可以通过域控中运行adsiedit.msc
打开。
常见的SPN实例
AcronisAgent:针对Acronis备份和数据恢复软件 |
这里有个不错的github有关SPN的项目:
RiskySPN
小结
kerberos认证的过程把其中的票据的生成和三者之间的关系弄清楚较为关键,我推荐B站有个视频讲的不错:
Kerberos UP主: ziaolin http://www.bilibili.com/video/BV1XW411e7Cs?share_medium=android&share_source=more&bbid=XYADBFAAC65F9C5F6DA603D4376B81D82AFF9&ts=1593051508078 |
后续打算再把Kerberos攻击的几种方式整理罗列一下,先给自己挖个坑……
参考链接
https://pentestlab.blog/2018/06/12/kerberoast/
http://www.harmj0y.net/blog/activedirectory/targeted-kerberoasting/
https://skypacer210.github.io/2014/04/09/kerberos-those-thing/
https://docs.microsoft.com/en-us/previous-versions/aa302203(v=msdn.10)#msdn_pac_request
https://tools.ietf.org/html/rfc1510