文章目录
关注公众号回复20231110获取最新网络安全以及内网渗透等资料。
Kerberos详解
Kerberos协议是一种基于票据的认证方式,客户端想要访问服务端的某个服务,无论是FTP,还是文件下载,任何需要认证的服务,都需要先去购买服务端认可的ST服务票据,但是这张票不能直接买,就好比我要买个东西,卖家告诉我你还没有资格买这个东西,把你的资格证拿出来,我才能卖给你,一听这,woc,这不扯淡么。所以kerberos就跟这个是一样的,你要买ST服务票据,你就得先去拿到TGT认购权证,只有你拿到了这个才有资格去购买,反正最终的目的是要去访问服务端提供的服务。
比如说啊,我们加入到域内的用户,然后我们去登录的时候使用wireshark抓包,可以看到:
那么这个TGT如何得到的呢?
TGT和ST这两个东西啊,都是KDC发放的,KDC是运行在域控上面的,他是一个网络服务,KDC也可以叫密钥分发中心,域控提供了一个账户专门来做这一件事情。这个账号就是krbtgt。
Kerberos协议有两个基础认证模块:AS_REQ & AS_REP 和 TGS_REQ & TGS_REP ,以及微软扩展的两个认证模块 S4U 和 PAC
这两个基础认证模块要做的事情就是证明客户端的身份,而S4U这个模块主要是为了实现委派而扩展的模块,分别为S4U2Self 和 S4U2Proxy,那么既然已经有基础模块来证明客户端的身份,但是没有模块证明客户端的权限啊,所以PAC是用来解决权限这个文件,PAC也叫特权属性证书。
Kerberos使用TCP/UDP 88端口进行认证,使用TCP/UDP 464端口进行密码重设。
如下域控运行这两个端口:
PAC特权属性证书
AC (Privilege Attribute Certificate,特权属性证书),其中所包含的是各种授权信息、附加凭据信息、配置文件和策略信息等。例如用户所属的用户组, 用户所具有的权限等。在最初的RFC1510中规定的标准Kerberos认证过程中并没有PAC,微软在自己的产品中所实现的Kerberos流程加入了PAC的概念,因为在域中不同权限的用户能够访问的资源是不同的,因此微软设计PAC用来辨别用户身份和权限。
在一个正常的Kerberos认证流程中,KDC返回的TGT认购权证和ST服务票据中都是带有PAC的。这样做的好处就是在以后对资源的访问中, 服务端再接收到客户请求的时候不再需要借助KDC的帮助提供完整的授权信息来完成对用户权限的判断, 而只需要根据请求中所包含的PAC信息直接与本地资源的ACL相比较做出裁决。
说白了就是前面两个基础认证模块是认证,PAC是授权。
如何抓包?
开启Wireshark之后使用kekeo申请一个TGT认购权证。
wireshark抓包情况:
然后将这个票据导入到内存中即可获取到TGS_REQ TGS_REP
这时你的wireshark会抓到包:
那么我们来分析一下PAC:
PAC我们之前说到过kerberos只提供了基础的认证服务,并没有提供这个人有什么权限可以访问什么服务,所以PAC就是干这个事情的。
PAC
在彻底分析PAC之前,建议先去看下面的内容,看完之后才回过头来看比较好点。
解密Kerberos数据包
在分析PAC之前需要将我们抓到的Kerberos数据包进行解密。
这里解密的话踩到几个坑。
大家可以参考这篇文件进行解密:https://mp.weixin.qq.com/s/eTiQRoEh1DvNGEuPErYsAw
但是在运行dskeytab.py文件的时候一直会提示没有Crypto.Hash。
这里我的解决方式是,我的是ubuntu的服务器,所以我是直接安装的python2,并且安装pip2。
使用pip2运行如下命令:
pip2 install pycryptodome
pip2 install crypto
pip2 install pycrypto
这里问题就解决了。
还有一个需要注意的问题是,这里的目录一定是你ntdsxtract的目录。其他目录可能会报错。
这里就获取到了1.keytab文件了。
生成完成之后可以使用ktutil查看当前keytab内的信息,如果需要使用ktutil命令需要安全kerberos客户端,我这里安装的是heimdal-clients,命令执行完,即可看到当前keytab中包含的信息。
sudo apt-get install heimdal-clients
ktutil -k 1.keytab list
紧接着导入到wireshark中。
编辑->首选项,导入即可。
可以看到如下表示解密成功。
那么我们来分析一下数据包:
AS_REQ
当某个域内的用户去访问域内的某个服务的时候,例如FTP,SMB,HTTP等服务的时候,输入账号和密码,这个用户所在的客户端就会向密钥分发中心(KDC)的AS认证(TGT认购权证都是由KDC的AS认证服务颁发的)服务发送一个AS_REQ的请求,里面包含着请求的用户名,域名,加密时间戳等等。
详细如下:
pvno: kerberos版本号,这里为5
msg-type: 消息类型, AS_REQ 对应的是 krb-as-req(10)
padata:主要是一些认证信息,每个认证消息有type和value。
PA-DATA PA-ENC-TIMESTAMP:这个是预认证,就是用用户Hash加密时间戳,作为value发送给KDC的AS服务。然后KDC从活动目录中查询出用户的hash,使用用户Hash进行解密,获得时间戳,如果能解密,且时间戳在一定的范围内,则证明认证通过。由于是使用用户密码Hash加密的时间戳,所以也就造成了哈希传递攻击
padata-type: padata类型,这里是 pA-ENC-TIMESTAMP(2)
padata-vaule: 加密后的值
etype: 加密类型,这里是 eTYPE-AES256-CTS-HMAC-SHA1-96(18)
cipher: 密钥
PA-DATA PA-PAC-REQUEST:这个是启用PAC支持的扩展。这里的value对应的值为True或False,KDC根据include的值来确定返回的票据中是否需要携带PAC。
padata-type: padata类型,这里是pA-PAC-REQUEST(128)
padata-vaule: padata的值
include-pac: 是否包含PAC,这里为True,说明要PAC
req-body:请求body
padding:填充,这里为0
kdc-options:用于与KDC协商一些选项设置
reserved
forwardable
forwarded
proxiable
proxy
allow-postdate
postdated
unused7
renewable
unused9
unused10
opt-hardware-auth
unused12
unused13
constrained-delegation
canonicalize
request-anonymous
unused17
unused18
unused19
unused20
unused21
unused22
unused23
unused24
unused25
disable-transited-check
renewable-ok
enc-tkt-in-skey
unused29
renew
validate
cname:请求的用户名,这个用户名存在和不存在,返回的包有差异,因此可以用于枚举域内用户名。并且当用户名存在,密码正确和错误时,返回包也不一样,因此也可以进行密码喷洒。
name-type:名字类型,这里是KRB5-NT-PRINCIPAL(1)
cnmae-string:名字,也就是请求的用户名
CNameString: 请求的用户名,这里为 hack
realm:域名,这里为XIE.COM
sname:请求的服务,包含type和Value。在AS-REQ里面sname始终为krbtgt
name-type:名字类型,这里是KRB5-NT-PRINCIPAL(1)
sname-string: krbtgt用户的信息,这里有2个items
SNameString: 这里是krbtgt用户名
SNameString: 这里是域名XIE.COM
till:到期时间
rtime:也是到期时间
nonce:随机生成的一个数
etype:加密类型
ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96(18)
这里的 PA-DATA PA-ENC-TIMESTAMP字段表示预认证,在AS_REQ请求包中,只有PA-DATA PA-ENC-TIMESTAMP部分是加密的,这一部分属于预认证,我们称这部分为Authenticator。
这个预认证这一块是通过用户的Hash或用户的密码的Aes Key来加密时间戳的,当加密完成之后,发送给KDC的AS服务,那么AS服务就会去活动目录中去查找到用户的Hash值,然后进行解密,如果解密成功并且时间戳是在一定的范围之内的话,那么表示认证成功。之所以是使用用户的Hash进行加密和解密的,所以就造成了Hash传递的攻击。
AS_REP
在这一阶段,KDC的AS服务收到客户端发送过来的AS_REQ的请求之后,从活动目录中取出该用户的密钥,然后对请求包中的Authenticator预认证部分进行解密,如果解密成功,并且时间戳在有效的范围内,则证明请求者提供的用户密钥正确。
认证成功之后,发送AS_REP响应包给客户端,在AS_REP响应包中里面存储着TGT认购权证。
AS_REP中包含如下信息:
1.请求的用户名。
2.域名。
3.TGT认购权证。包含明文的版本号,域名,请求的服务名,以及加密部分enc-part。加密部分用krbtgt密钥加密。加密部分包含Logon Session Key、用户名、域名、认证时间、认证到期时间和authorization-data。authorization-data中包含最重要的PAC特权属性证书(包含用户的RID,用户所在组的RID) 等。
4.enc_Logon Session Key使用用户密钥加密Logon Session Key后的值,其作用是用于确保客户端和KDC下阶段之间通信安全。也就是AS-REP中最外层的enc-part。
Logon session key是通过用户的Hash进行加密的,用作下一阶段的认证密钥,TGT认购权证中的加密部分是通过krbtgt密码Hash进行加密的,因此如果我们拥有krbtgt的hash就可以自己制作一个ticket,这就造成了黄金票据攻击。
详细:
pvno:kerberos版本号,这里为5
msg-type:消息类型,AS_REP对应的是 krb-as-rep(11)
padata:主要是一些认证信息。一个列表,包含若干个认证消息用于认证
PA-DATA PA-ENCTYPE-INFO2
padata-type: padata的类型,这里是 pA-ETYPE-INFO2(19)
padata-value: 加密后的值
ETYPE-INFO2-ENTRY
etype: eTYPE-AES256-CTS-HMAC-SHA1-96(18)
salt: 盐值,这里是 XIE.COMhack
crealm: 域名,这里是XIE.COM
cname:请求的用户名
name-type: 用户名类型,这里是 kRB5-NT-PRINCIPAL(1)
cname-string: 1item
CNameString: hack
ticket:TGT认购权证
tkt-vno: TGT版本号,这里为5
realm: 域名,这里是 XIE.COM
sname: 服务用户名,这里是krbtgt 密码分发中心服务账号
name-type: KRB5-NT-SRV-INST(2)
sname-string: 2items
SNameString: krbtgt
SNameString: XIE.COM
enc-part: TGT票据中的加密部分,这部门是用krbtgt的密码Hash加密的。因此如果我们拥有krbtgt的hash就可以自己制作一个ticket,这就造成了黄金票据攻击
etype: 加密类型,这里是 eTYPE-AES256-CTS-HMAC-SHA1-96(18)
kvno: 版本号,这里为2
cipher:加密后的值
enc-part:Login session key,这部分是用请求的用户密码Hash加密的,作为下阶段的认证密钥。
etype: eTYPE-AES256-CTS-HMAC-SHA1-96(18)
kvno: 版本号,这里为3
cipher:加密后的值
TGT认购权证
AS-REP响应包中的ticket便是TGT认购权证了,TGT认购权证中包含版本号,域名realm,请求的服务名sname以及加密部分也就是enc-part,这里面分别包含了用户名cname 域名realm,认证的时间,以及认证到期的时间等等。
最重要的还是authorization-data部分,这部分包含了客户端的身份权限等信息,这些信息包含在PAC中。
KDC生成PAC的过程如下:KDC在收到客户端发送过来的AS_REQ请求后,从请求中取出cname字段,然后查询活动目录数据库,找到sAMAccountName属性为cname字段的用户,用该用户的身份生成一个对应的PAC。
例如:点击查看->高级功能 然后右键属性找到属性编译器即可找到这个属性。
Logon Session Key
AS_REP最外层的加密部分就是Logon Sesion Key了,它的作用主要是确保客户端和KDC阶段之间的通信安全,它使用请求的用户密钥加密。
TGS_REQ
客户端在收到KDC的AS_REP回复后,使用用户的Hash解密enc_Logon Session Key(也就是最外层的enc-part),得到Logon Session Key,并且也拿到了TGT认购权证,之后他会在本地缓存此TGT认购权证和Logon Session Key。在客户端需要凭借这张TGT认购凭证向KDC购买相应的ST服务票据(Service Ticket)。ST服务票据是KDC的另一个服务 TGS(Ticket Granting Service)票据授予服务发放的。
**TGS-REQ:**客户端拿着上一步获得的TGT认购权证发起TGS-REQ请求,向KDC购买针对指定服务的ST服务票据,该请求主要包含如下信息:
域名(realm)。
请求的服务名(sname)。
TGT认购权证。
Authenticator:一个抽象的概念,代表一个验证。这里使用Logon Session Key加密的时间戳。
加密类型(etype)。
以及一些其他信息:如版本号,消息类型,协商选项,票据到期时间等。
pvno:kerberos版本号,这里为5
msg-type:消息类型,TGS_REQ对应的是 krb-tgs-req(12)
padata:padata中包含ap_req,这个是TGS_REQ必须携带的部分,这部分会携带AS_REP里面获取到的TGT认购权证和使用原始的Logon Session Key加密的时间戳。还有可能会有PA_FOR_USER,类型是S4U2SELF,是一个唯一的标识符,该标识符指示用户的身份,该标识符由用户名和域名组成。S4U2Proxy必须扩展PA_FOR_USER结构,指定服务代表某个用户去请求针对服务自身的kerberos服务票据。还有可能会有PA_PAC_OPTIONS,类型是PA_PAC_OPTIONS。S4U2Proxy必须扩展PA-PAC-OPTIONS结构。如果是基于资源的约束委派,就需要指定Resource-based Constrained Delegation位。
padata-type: padata类型,这里是 pA-TGS-REQ(1)
padata-value: padata的值
ap-req:这个是TGS_REQ必须携带的部分
pvn0:5
msg-type:krb-ap-req(14)
padding:0
ap-options:00000000
reserved: False
use-session-key: False
mutual-required: False
ticket AS-REP响应包中返回的TGT认购权证
tkt-vno:5
realm: XIE.COM
sname
name-type: kRB5-NT-SRV-PRINCIPAL(1)
sname-string:2 items
SNameString: krbtgt
SNameString: XIE.COM
enc-part
etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
kvno: 2
cipher: 加密后的值
authenticator: 原始Logon Session Key加密的时间戳,用于保证会话安全
etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
cipher: 加密后的值
req-body:请求body
padding:这里为0
kdc-options:用于与KDC约定一些选项设置
reserved
forwardable
forwarded
proxiable
proxy
allow-postdate
postdated
unused7
renewable
unused9
unused10
opt-hardware-auth
unused12
unused13
constrained-delegation
canonicalize
request-anonymous
unused17
unused18
unused19
unused20
unused21
unused22
unused23
unused24
unused25
disable-transited-check
renewable-ok
enc-tkt-in-skey
unused29
renew
validate
realm:域名,这里为XIE.COM
sname:要请求的服务名
name-type: KRB5-NT-SRV-INST(2)
sname-string: 2 items
SNameString: cifs
SNameString: win10.xie.com
till:到期时间,rubeus和kekeo都是20370913024805Z,这个可以作为特征来检测工具。
nonce:随机生成的一个数。
etype:加密类型
ENCTYPE: eTYPE-ARCFOUR-HMAC-MD5(23)
ENCTYPE: eTYPE-DES3-CBC-SHA1(16)
ENCTYPE: eTYPE-DES-CBC-MD5 (3)
ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96(18)
为了确保后阶段的会话安全,TGS-REQ中ap-req中的authenticator字段的值是用上一步AS-REP中返回的Logon Session Key加密的时间戳
TGS_REP
KDC的TGS服务接收到TGS-REQ请求之后。首先使用krbtgt密钥解密TGT认购权证中加密部分得到Logon Session key和PAC等信息,如果能解密成功则说明该TGT认购权证是KDC颁发的。然后验证PAC的签名,如果签名正确,则证明PAC未经过篡改。然后使用Logon Session Key解密Authenticator得到时间戳等信息,如果能够解密成功,并且票据时间在范围内,则验证了会话的安全性。在完成上述的检测后,KDC的TGS服务完成了对客户端的认证,TGS服务发送响应包给客户端。
请求的用户名(cname)
域名(crealm)
ST服务票据:包含明文的版本号,域名,请求的服务名,以及加密部分enc-part,加密部分用服务密钥加密。加密部分包含用户名、域名、认证时间、认证到期时间、Service Session key和authorization-data。authorization-data中包含最重要的PAC特权属性证书(包含用户的RID,用户所在的组的RDI) 等。
enc_Service Session key:使用Logon Session key加密的Service Session key,其作用是用于确保客户端和KDC下阶段之间通信安全。
这里需要说明的是,TGS-REP这步中KDC并不会验证客户端是否有权限访问服务端。因此,这一步不管用户有没有访问服务的权限,只要TGT正确,均会返回ST服务票据,这也是kerberoasting能利用的原因,任何一个域内用户,都可以请求域内任何一个服务的ST服务票据。
pvno:kerberos版本号,这里为5
msg-type:消息类型,TGS_REP对应的是 krb-tgs-rep(13)
crealm: 域名,这里是XIE.COM
cname:请求的用户名
name-type: 名称类型,这里为 KRB5-NT-PRINCIPAL(1)
cname-string: 1 item
CNameString: hack
ticket:即ST服务票据
tkt-vno: 服务票据版本号,这里为5
realm: 域名,这里是XIE.COM
sname:
name-type: KRB5-NT-SRV-HST(3)
sname-string: 2 items
SNameString: cifs
SNameString: win10.xie.com
enc-part: 这部分是用服务的密钥加密的
etype: 加密类型,eTYPE-AES256-CTS-HMAC-SHA1-96(18)
kvno: 版本号,这里为3
cipher:加密后的值
enc-part:这部分是用原始的Logon Session Key加密的。里面最重要的字段是Service session key,作为下阶段的认证密钥。
etype: 加密类型eTYPE-AES256-CTS-HMAC-SHA1-96(18)
cipher: 加密后的值
TGS-REP返回包中最重要的就是ST服务票据和Service Session key了。ST服务票据中加密部分是使用服务密钥加密的,而Service Session key是使用Logon Session Key加密的。
ST服务票据
TGS-REP响应包中的ticket便是ST服务票据了。ST服务票据中包含明文显示的信息,如版本号tkt-vno、域名realm、请求的服务名sname。但是ST服务票据中最重要的还是加密部分,加密部分是使用服务密钥加密的。加密部分主要包含的内容有Server Session Key、请求的用户名cname、域名crealm、认证时间authtime、认证到期时间endtime、authorization-data等信息。最重要的还是authorization-data部分,这部分中包含客户端的身份权限等信息,这些信息包含在PAC中。
PAC中包含了用户身份权限等信息,如下图:这里最重要的还是通过User RID和Group RID来辨别用户权限的。可以看到,ST服务票据中的PAC和TGT认购权证中的PAC是一致的,在正常的非S4u2Self请求的TGS过程中,KDC在ST服务票据中的PAC是直接拷贝TGT票据中的PAC。
Service Session Key
TGS-REP响应包最外层的那部分便是Service Session Key了,其作用是用于确保客户端和KDC下阶段之间通信安全,它使用Logon Session Key加密。
如图所示,对其进行解密,它主要包含的内容是认证时间authtime、认证到期时间endtime、域名srealm、请求的服务名sname、协商标志flags等一些信息。需要说明的是,在ST服务票据中也包含Service Session Key。
域用户枚举攻击
走了那么多流程,未免有些枯燥了,我们来看一下kerberos协议中可能产生的安全问题。
域内用户枚举主要是发生在AS_REQ的阶段,在我们想要去访问域内某个服务的时候,向KDC的AS服务发送AS_REQ请求,里面包含着域名,用户名,加密时间戳以及预认证,预认证这一块是通过用户的Hash加密时间戳获得的。
那么既然里面包含着用户名也就是cname这个字段值,当使用一个不存在的用户名时,报错。
我们使用MSF攻击并使用wireshark抓包:
这里使用的是auxiliary/gather/kerberos_enumusers模块进行域内用户枚举。
wireshark抓包情况:
我们可以发现他发的包都是AS_REQ的包,并且我们可以看到它返回的值是不一样的,有些是报错了,我们点进去查看cname的值。
可以发现其实改变的就是cname的值,通过报错来进行判断的。
关于域内用户枚举除了MSF工具也可以使用其他的工具。
例如:pyKerbrute
下载: https://github.com/3gstudent/pyKerbrute
域用户密码喷洒
这个漏洞也是出现在AS_REQ阶段中,当输入的用户名正确如果密码不正确的话返回的包也是不一样的,所以可以使用密码喷洒攻击。
一般我们都会使用一对多的形式来进行密码喷洒,就比如说收集到很多的域内账户,我们就可以使用一个密码对多个域用户进行密码喷洒。
使用MSF进行密码喷洒:
这里使用的是 use scanner/smb/smb_login 这个模块。
可以看到已经喷洒出来了。
不仅可以使用MSF,也可以使用pyKerbrute来进行喷洒。这里就不演示了,给出命令。
pyKerbrute进行密码喷洒命令:
针对明文密码进行喷洒:
TCP模式:
python2 ADPwdSpray.py 10.211.55.100 test.com user.txt clerpassword P@ass123 tcp
UDP模式:
python2 ADPwdSpray.py 10.211.55.100 test.com user.txt clerpassword P@ass123 udp
针对密码hash进行喷洒
TCP模式:
python2 ADPwdSpray.py 10.211.55.100 test.com user.txt ntlmhash xxxxxxxx tcp
UDP模式:
python2 ADPwdSpray.py 10.211.55.100 test.com user.txt ntlmhash xxxxxxxx udp
黄金票据攻击
在AS_REP阶段,由于返回的TGT认购权证是由krbtgt用户的密码Hash加密的,因此如果我们拥有krbtgt的密码hash就可以制作一个TGT认购权证。同样在TGS_REP阶段返回的ST服务票据是使用服务的hash进行加密的,如果我们拥有服务的hash,那么就可以将这个服务签发给任意用户,这个票据就是白银票据。那么这两个的区别就是黄金票据使用krbtgt的hash构造的,白银票据是使用服务的hash构造的。
这个后面会演示到。
AS-REP Rasting攻击
Logon session key是用用户密码 Hash 加密的,对于域用户,如果设置了不要求kerberos预身份验证,也就是如下图:、
此时攻击者可以直接向域控制器的 88 端口发送 AS_REQ 请求,此时域控不会做任何验证就将 TGT认购权证 和 该用户Hash加密的Login Session Key返回。因此,攻击者就可以对获取到的 用户Hash加密的Login Session Key进行离线破解,如果破解成功,就能得到该用户的密码明文,因为原本AS_REQ是需要预认证的。
使用Powershell查找域中设置了 "不需要kerberos预身份验证"的用户。
工具下载地址:
https://github.com/EmpireProject/Empire/tree/master/data/module_source/situational_awareness/network
可以看到已经查询到了不需要kerberos预身份验证的用户。如图是hack用户。
那么我们就可以通过ASREPRoast工具获取Hash最后进行暴力破解。
工具下载地址:https://github.com/HarmJ0y/ASREPRoast/
Import-Module .\ASREPRoast.ps1
Get-ASREPHash -UserName hack -Domain relaysec.com | Out-File -Encoding ASCII hash.txt
接下来就可以使用HashCat进行破解了,但是一般默认情况下域用户都不会开启不需要kerberos预身份验证。
这一章目前就先写到这里。