简介
该漏洞能使普通域用户提权为域管理员权限
1 | *环境:* |
漏洞利用
获取域用户的SID、域控主机group
1 | whoami /user |

使用pykek的漏洞利用程序进行攻击

进行攻击前需知道用户名、密码、SID、域控主机地址,在pykek-master的文件夹下生成了TGT_mary@GOD.ORG.ccache票据,需借助mimikatz将票据写入内存中,创建缓存证书。在此操作之前我们可以用klist命令看下缓存的证书有哪些。发现有五个缓存,如果此时不进行清除直接将TGT票据写入内存,在之后进行请求服务时,系统会从Credentials Cache中查看是否有对应的ServiceTicket(未清除时缓存的证书还是普通域用户的权限),如果没有找到则寻找TGT,找到后就发送给KDC申请ServiceTicket。
清除缓存证书,mimikatz写入
1 | Klist |



请求高权限服务
1 | net use \\OWA2010CN-GOD\C$ |

漏洞细节分析
PAC的一些理解
在kerberos协议里,client向server发起请求,serever解密ST证实了client身份,但不知道client有没有访问文件的权限。微软在kerberos协议里扩充了PAC(Privilege Attribute Certificate)。
在AS_REQ请求时引入了include-pac项,include-pac为True时,AS_REP里ticket会携带PAC。PAC中包含了client的UserId、GroupIds、ExtraSids、ResourceGroupDomainSid等,PAC包含了两个数字签名,一个是Server Signature另一个是KDC Signature。微软给出的文档 “For the server’s checksum, the key used to generate the signature should be the same key used to encrypt the ticket.” https://docs.microsoft.com/en-us/previous-versions/aa302203(v=msdn.10)#signatures-pac_server_checksum-and-pac_privsvr_checksum
对client和AS服务来说server指的是TGS服务,AS和TGS的密码就是krbtgt用户的NTLM hash。两个数字签名和TGT加密时用的key相同但加密算法不同。
Client解密得到加密的TGT,在TGS_REQ中携带TGT发送给TGS,在认证了client的信息后,将解密PAC并验证两个签名,如果签名合法则认为PAC没有被篡改。此时将更换PAC的两个签名,根据前面已经知道key与ticket相同,所以此时两个数字签名的key为server的NTLM hash。
在AP_REQ阶段携带ST请求server,server解密得到PAC并向KDC确认client用户权限,KDC将结果返回至server。
漏洞利用的流程
1 | build AS-REQ -> send AS-REQ |
附上部分相关代码:
1 | as_req = build_as_req(user_realm, user_name, user_key, current_time, nonce, pac_request=False) |
上面流程中比较奇怪的一点是,在recv AS_REP后解密却得到了TGT_b,正常的流程不应该是得到Service Ticket吗?这也是漏洞成因,下面结合数据包分析流程。
构造AS_REQ
看一下代码的结构,其中include-pac被设置成了False,对比一下抓取的数据包


左侧为构造的数据,右侧为正常的数据包,能够清楚的看到include-pac设置为False,kdc-options由常见的0x40810010设置为0x50800000,加密方式为eTYPE-ARCFOUR-HMAC-MD5 (23),正常的数据包采用 eTYPE-AES256-CTS-HMAC-SHA1-96 (18)加密方式这一点我们也能从代码结构中看到:

之所以将include-pac设置为False,是因为AS收到AS_REQ时,对include-pac值进行判断,在AS通过认证后返回的数据包中不包含PAC的信息。若include-pac值为True,将在AS_REP中的TGT加入PAC信息。
接收AS_REP
可以看到用user_key解密得到16位的session_key(用于后续通讯),和使用krbtgt的ntlm hash加密的TGT_a(不含PAC信息)


通过对比两个数据包,发现左侧返回的内容缺少了padata部分,使用的加密方式依旧是etype: eTYPE-ARCFOUR-HMAC-MD5 (23)
构造PAC
下面是PAC的结构图

在PACTYPE structure里有一个重要的KERB_VALIDATION_INFO structure,它定义了用户登录、授权的一些信息。其中有UserId、PrimaryGroupId(用户所在的组)。接下来我们看一下pykek是怎么构造的PAC


1 | # 域用户(513) |
从上面我们可以看到把域用户加入到了域管理员等5个组,从而具有了域管的权限。但是我们在前面提到过,PAC最后需要有使用server_key和KDC_key的加密的两个签名。但这里并不知道krbtgt用户的NTLM hash,那是怎么制作的PAC呢?
漏洞一:KDC无法正确检查票据中所携带的特权属性证书(PAC)的有效签名。
这也就意味着我们可以伪造PAC,不使用原本要用到的HMCA系列的checksum算法,原来的算法需要key参与才能生成签名。如果使用MD5算法便不需要key参与,这样便可随意修改PAC的内容,最后使用MD5生成服务检验和以及KDC校验和。现在PAC做好了,但是PAC是附在TGT里面,TGT是使用krbtgt用户的NTLM hash进行加密的,这里并不知道密钥,那是怎么把PAC传输给KDC呢
漏洞二:KDC能够解析放在其它位置上PAC内容
构造TGS_REQ
从下面的图片可以看出作者将PAC放入了req_body下面的enc-authorization-data里面,其中ad-type是加密算法,ad-data是PAC加密的内容。加密的subkey是随机生成的,KDC也不知道,所以作者将subkey与TGT一块放入了ap-req里。




接收TGS-REP
通过下面图片我们可以看到使用subkey进行解密,解密后竟然得到了一个session_key和TGT,按照之前的kerberos协议应该返回一个使用请求服务的NTLM HASH进行加密的ST(server ticket)。
漏洞三:按照之前的设置在TGS_REQ请求后,KDC会从authorization中解密出subkey,对PAC进行签名验证。同时还会对TGT进行解密得到SessionKeya-kdc。在验证成功后还会对解密的PAC使用server_key和kdc_key进行签名,重新组合成一个TGT,并把SessionKeya-kdc使用subkey加密发送给client。

换取ST
此时我们已经有了TGT,并将票据凭证写入了内存。但是还没有ST,需要利用缓存的TGT再次发送TGS_REQ。下面是使用net use \OWA2010CN-GOD\C$的抓包。比较奇怪的是TGS_REQ和TGS_REP进行了三个来回。

接下来查看73和74组数据包里内容,发现请求了cifs服务的ST。

接下来查看81、82两个数据包发现依旧是携带TGT请求krbtgt服务的ST,但是authenticator的加密类型是eTYPE-ARCFOUR-HMAC-MD5 (23),但下面的支持类型只有一种ENCTYPE: eTYPE-AES256-CTS-HMAC-SHA1-96 (18),所以在TGS_REP中返回了error-code: eRR-ETYPE-NOSUPP (14)

接下来查看89和90两个数据包,在etype添加了可支持的加密类型,返回了ST,票据的加密类型为etype: eTYPE-ARCFOUR-HMAC-MD5 (23)

此时我们再用klist命令查看本地的缓存证书发现多出来了两个,正是刚才申请的ST证书。

之后经过TCP握手后再基于SMB协议携带ST请求服务


至此整个漏洞利用流程已经完成,可能在一些细节理解有误,恳请指正。
参考链接
https://www.freebuf.com/vuls/56081.html