MS14-068(CVE-2014-6324)
参考:
深入解读MS14-068漏洞:微软精心策划的后门?——walkerfuz
Kerberos Vulnerability in MS14-068 (KB3011780) Explained
Windows–protocol:Kerberos篇-PAC——daiker
注:建议必读daiker的这篇,相比起他的,我的就是皮毛
MS-PAC : Privilege Attribute Certificate Data Structure
注:建议阅读上面的参考链接,本文只是笔者学习前辈的分享记录所得。
对应的补丁为:KB3011780
利用过程
先直接看下该漏洞的效果:
1 | MS14-068.exe -u jack@0day.org -s S-1-5-21-1812960810-2335050734-3517558805-1133 -d OWA2010SP3.0day.or |
看起来和之前的黄金票据有点类似,结果是生成了一张黄金票据,能够访问任何服务(包括域控)。
impacket中也提供了方便的脚本goldenPac.py,如果没有python 环境,推荐使用代理或者使用impacket 的exe版
1 | goldenPac.exe 0day.org/jack@OWA2010SP3 -hashes 00000000000000 |
Pac 特权属性证书
参考:
PAC在Kerberos认证协议中的作用(一)——微软文档,推荐
什么是Pac(Privilaged Attribute Certificate ,特权属性证书),Pac是Microsoft引入的Kerberos 扩展,Kerberos设计的流程证明Client的身份,但没有声明Client的权限,在域中不同权限访问不同用户是有区别的,而PAC就是为了区别不同权限的一种方式。
1 | reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerber |
在Impacket中提供了GetPac来获取特权属性证书。
1 | #请将DNS指向域控,或者在hosts文件中指定域和地址,否则无法解析正确解析域名 |
注:本来想弄并排效果的,没有折腾成功。
这个结构可对照参考链接中的MS-PAC协议规范查看。
1 | typedef struct _KERB_VALIDATION_INFO { |
Pac中包含各种授权信息,比如UserSID、PrimaryGroupID、GroupIDs等,我进行了两次用户的PAC证书获取,最大的不同在GroupIDs和UserID。
使用Powersploit中的Get-DomainGroup
也能查询的对应的结果,并且结果更加全面。
1 | Get-DomainGroup -MemberIdentity administrator |Select-Object samaccountname,objectsid |
在域控中可验证查询到的信息是准确的。
回到特权属性证书的话题,Pac包含在TGT中,为了防止内容被篡改,存在两个签名,分别是目标服务和KDC的签名,对于TGT来说,这个两个账户的密钥都是krbtgt账户的密钥。
有了Pac参与后,Kerberos认证过程是怎么样的呢?
注:以下这段大部分都来自微软文档,建议阅读该文档
KRB_AS_REQ:Client向KDC的AS申请TGT,消息包括用户主体名称、域名和预认证信息,预认证信息使用用户的密钥加密
注:注意这里的描述为密钥,而不是NTLM hash ,NTLM hash只是密钥的一种,密钥可以是ntlm和aes key 等。
KRB_AS_REP:AS生成TGT,生成一个Session key 。KDC收到KRB_AS_REQ之后,从数据库(ntds.dit)中用户的密钥,解密预认证信息,验证用户生成TGT和Session Key(Client/KDC Session Key) 。TGT中包含Session Key 和Pac(特权属性证书),TGT使用KDC的密钥(krbtgt)加密,Session Key 使用用户密钥加密,返回用户。
KRB_TGS_REQ:用户提供TGT、Authenticator 1和服务主体名向TGS申请ST(Service Ticket)。用户收到KRB_AS_REQ后,使用自己的密钥解密Session Key ,保存该密钥在证书缓存中。用户准备一个使用Session Key(Client/KDC Session Key)加密的 Authenticator 1,连同TGT和服务主体名发送给KDC。
KRB_TGS_REP :TGS生成ST。KDC收到KRB_TGS_REQ之后,使用自己的密钥(krbtgt)解密TGT,得到Session Key (Client/KDC Session Key),用它解密 Authenticator 1,验证用户的有协议。验证过程后,生成一个Session Key (Client/Server Session Key)和ST。Session Key (Client/Server Session Key)使用Session Key(Client/KDC Session Key)加密。ST中包含Session Key (Client/Server Session Key)和Pac,使用Server 的密钥加密。KDC返回两者给用户。
KRB_AP_REQ:用户将ST和authenticator 2发送给服务端,申请访问。用户收到KRB_TGS_REQ之后,使用Session Key(Client/KDC Session Key)解密Session Key (Client/Server Session Key),将Session Key (Client/Server Session Key)保存在证书缓存中。用户准备一个用Session Key (Client/Server Session Key)加密的authenticator 2,连同 ST 和一些标志位发送给服务端。
KRB_AP_REP:可选,当用户希望验证提供服务的服务端,服务端返回该消息。服务端收到KRB_AR_REQ之后,用服务的密钥解密ST,得到Session Key (Client/Server Session Key),使用Session Key (Client/Server Session Key)解密authenticator 2,验证用户。验证通过之后,生成访问令牌。同时,服务端检查相互验证的标志位是否置位,如果置位,会从authenticator 2 中获得的时间戳生成新的authenticator 3,使用Session Key (Client/Server Session Key)加密,返回给用户
用户收到KRB_AP_REP消息之后,使用Session Key (Client/Server Session Key)解密authenticator 3,验证服务正确性。
Pac在Kerberos认证过程中如何工作?
当用户与KDC之间完成了认证过程之后, 用户需要访问服务器所提供的某项服务时, 服务器为了判断用户是否具有合法的权限必须通过将用户的用户名传递给KDC, KDC通过得到的用户名查询用户的用户组信息, 用户权限等, 进而返回给服务器, 服务器再将此信息与用户所索取的资源的ACL进行比较, 最后决定是否给用户提供相应的服务。
KRB_AS_REP信息中将包含一组PAC信息, 也就是说, 用户所得到的TGT(TicketGranting Ticket)会包含用户的授权信息。用户再用包含有授权信息的TGT去申请相应的Service Ticket,KDC在收到这个KBR_AP_REQ请求的时候, 将TGT里的PAC信息解析出来, 加入到Service Ticket里返回。接下来, 当用户向服务器程序提交KRB_AP_REQ消息时, 服务器程序则将其中所包含的PAC信息传送给操作系统得到一个访问令牌, 并且同时将这个PAC的数字签名以KRB_VERIFY_PAC的消息传输给KDC, KDC再将验证这个PAC的数字签名的结果以RPC返回码的形式告诉服务器, 服务器就可以根据这个结果判断PAC数据的真实性和完整性,并做出最后对KRB_AP_REQ的判断。
注:这段真的写的非常好,至此我觉得需要了解的已经足够,建议阅读这篇博文和MS-Pac规范。
MS14-068原理
Digging into MS14-068, Exploitation and Defence
先说原因:KDC无法验证Kerberos 票证中的特权属性证书签名。
前面在介绍Pac的时候提过,有两个签名,分别是Server Signature、KDC Signature。在Ms-Pac 规范中规定了签名的算法只有为Hmac系列的checksum算法,也就是KERB_CHECKSUM_HMAC_MD5、HMAC_SHA1_96_AES128、HMAC_SHA1_96_AES256。但是在实现上,却允许所有的签名算法。上面在PAC的结构中,一个普通域用户和域管理员的PAC最大的不同之处在于用于所属的组不同,如果在Pac中加入高权限组,完了之后进行签名,在最后server和KDC验证阶段,KDC将给予用户高权限。
但是出现一个问题?PAC包含在TGT中,TGT使用krbtgt的 hash加密。即使可以伪造Pac,如何将票据传输给KDC呢,pykey的作者将PAC加密生成密文放在TGS-REQ消息的enc-authorization-data虽然该字段已加密,使用的密钥为用户已知的,在Authenticator中指定。
直接说过程,详细的原理笔者限于认识无法更为详细,这里做下笔记,可能未来有机会进行代码实现。
大体流程就是KDC拿到TGS_REQ之后,提取里面authenticator的密文,用session_key解密获得subkey,再使用subkey解密enc-authorization-data获得PAC——daiker
#貌似原文有错,原文是AP_REQ,这里应该是TGS_REQ
那么这个漏洞是如何实现的?这里以pykek的作者实现方式说明。
在AS_REQ阶段将PA-DATA PA-PAC-REQUEST中include-pac设置为False来请求不包含Pac的有效TGT。确保
和TGT中的合法PAC与其他地方伪造的Pac之间没有冲突。
注:只要能够请求到有效的TGT就能执行该攻击,换句话说,得到普通域用户成员和密码(或者NTLM)发起请求即可。
如前面所说,将Pac中添加高权限组成员,使用md5进行签名,存放在enc-authorization-data字段中,结构如下图。
总结下步骤:
- 通过发送PA-PAC-REQUEST设置为false的AS-REQ请求不带PAC的TGT。
- 伪造一个声称拥有域管理员成员资格的PAC。使用纯MD5对其“签名”。
- 创建一个以krbtgt为目标的TGS-REQ消息。第一步中的TGT与使用子会话密钥加密的伪PAC一起使用。将其发送到易受攻击的域控制器。
1 | tcp.port == 88 or udp.port == 88 #wireshark 语法 过滤KRB5流量 |
更多的工具
- kekeo
1 | exploit::ms14068 /domain:0day.org /user:jerry /password:Admin12345 /sid:S-1-5-21-1812960810-2335050734-3517558805 /ptt |
- impacket
除了前面的goldenPac.py脚本,daiker师傅给出了如何使用impacket使用票据进行验证的技巧。
1 | export KRB5CCNAME=TGT_jerry@0day.org.ccache |
- net相关的命令
1 | #这个工具和MS14-068无关,这里也说一下 |
总结
这篇笔记写了很久,期间很大部分时间试图理解Pac的结构上,可以看到我的上一篇博客是解密Kerberos流量,就是这个过程产生的。同时参考几篇博客和杨老师的kerberso系列,信息量给的越多,理解的难度也就越高,
这也给自己提了醒,在学习的过程中不要执着于某个点,先进行下去,再回过头来看一些内容就会变得容易理解。
也不要像笔者这样,博客这一篇看一点,哪一篇看一点,一定要完整读完一篇,理解作者的思路,才有助于理解。
可以发现daiker师傅在协议和底层上的理解很到位,但明显我的知识量跟不上,无法理解MS-Pac规范,只能囫囵吞枣,挑了一下自己看的懂得,可能读者看完也不明白我在写什么,只能说给自己做了个记录,看到时能够快速回想起来。