1、漏洞概述
2022年10月27日,ProjectZero安全研究员James Forshaw在博客中公开了2022 年 6 月发现并上报给微软官方的Kerberos提权漏洞的技术细节,漏洞成因是Kerberos在RC4_MD4加密算法的实现上存在一定缺陷,导致可被攻击者利用对加密过程中的密钥流进行暴力破解,实现权限提升,此次披露一共两个漏洞,分别被分配CVE-2022-33647与CVE-2022-33679两个编号。
CVE-2022-33647,该漏洞导致攻击者可进行中继攻击,通过修改AS-REQ包中etype字段进行强制加密降级到RC4 _MD4,对加密session_key使用的密钥流进行破解,从而实现权限提升。
CVE-2022-33679,该漏洞导致攻击者可请求设置了“不要求Kerberos预身份验证”的用户的TGT票据,并对AS-REP中加密session_key使用的密钥流进行破解,从而实现权限提升。
该漏洞的利用,需要攻击者可操作进出KDC的流量,进行中间人攻击,或者存在设置了“不要求Kerberos预身份验证”的用户,攻击者可在最多发送1280个请求后成功爆破密钥流,且不会触发域内密码策略导致账号锁定。
本文将详细分析该漏洞的产生及利用过程,以及对该漏洞的防御及检测方案。
2、漏洞复现
漏洞披露后,中安网星御守实验室第一时间对漏洞原理进行详细分析,并进行武器化工作,漏洞利用主要分为CVE-2022-33647、CVE-2022-33679、权限维持三部分。
CVE-2022-33647
CVE-2022-33647漏洞本身为中间人攻击,我们涉及在对这个洞的实现过程中我们考虑能不能通过强制认证结合CVE-2022-33647进行密钥流的爆破实现,这一部分涉及到Kerberos Relay,篇幅有写长我们不在本文展开讲,在此贴出部分参考链接,对此感兴趣的可以先提前看一看。
https://dirkjanm.io/krbrelayx-unconstrained-delegation-abuse-toolkit/
https://dirkjanm.io/relaying-kerberos-over-dns-with-krbrelayx-and-mitm6/
在进行结合利用的过程中,可以适当地打开思路,会有跟多有意思的发现,后面我们会单独以一篇文章详细介绍Kerberos Relay的新利用。
CVE-2022-33679
设置账户为“不要求Kerberos预身份验证”
利用漏洞利用脚本攻击该用户,将在一分钟之内成功爆破出密钥流,并通过TGS请求krbtgt的服务票据从而获取该用户的TGT票据。
权限维持
在获取到域管理员权限后,利用该手法为域控机器账户修改UAC添加“不要求Kerberos预身份验证”,从而实现权限维持。
3、漏洞分析
在详细了解漏洞原理之前,有一些前置内容需要铺垫:
Kerberos域身份认证,该漏洞的利用会反复提及Kerberos域身份认证,因此我们会简要介绍Kerberos预身份认证相关知识。
Windows 中RC4算法缺陷,该漏洞产生的根本原因是因为Windows中RC4-MD4算法的实现存在一定的缺陷,因此我们会介绍与Windows中RC4_MD4实现相关的一些知识。
DER编码,Kerberos的所有数据包均使用DER进行编码,为方便理解漏洞我们会介绍部分DER编码相关知识。
Kerberos预身份认证
在kerberos预认证(AS_REQ)过程中,客户端会利用自己密码的Hash将时间戳加密发送给KDC,KDC在接收到 AS_REQ之后利用自己存储的用户Hash解密出时间戳,如果时间差在规定的范围内就会给用户返回TGT票据(AS_REP),除了TGT票据, AS_REP还包含用户Hash加密的EncASRepPart,这个结构中包含下一步TGS_REQ/TGS_REP使用的加密密钥(session_key)。
时间戳包含在PA-ENC-TS-ENC结构中
PA-ENC-TS-ENC ::= SEQUENCE {
patimestamp [0] KerberosTime,
pausec [1] Microseconds OPTIONAL
}
session_key在EncASRepPart结构中
EncASRepPart ::= SEQUENCE {
key [0] EncryptionKey,
last-req [1] LastReq,
nonce [2] UInt32,
key-expiration [3] KerberosTime OPTIONAL,
flags [4] TicketFlags,
authtime [5] KerberosTime,
starttime [6] KerberosTime OPTIONAL,
endtime [7] KerberosTime,
renew-till [8] KerberosTime OPTIONAL,
srealm [9] Realm,
sname [10] PrincipalName,
caddr [11] HostAddresses OPTIONAL
}
Windows加密算法
在Windows中,所有的加密算法都在动态链接库cryptdll.dll中实现,虽然没有相关的详细资料,但是我们可以通过对cryptdll.dll进行逆向,或者通过阅读Windows XP(NT5)的源码来了解其相关的函数,下图是在cryptdll.dll对于加密函数的一些支持类型。
加密算法实现了加密key的生成、消息加密,签名等一系列安全措施,这其中既包含了我们在kerberos中常见的RC4_HMAC、AES256,也包含其他一些较为古老且存在安全隐患的算法,如RC4_MD4,现在Windows中已经找不到对于RC4_MD4算法的配置项了,因为该类型为负值表示的私有加密类型,然而我们在Kerberos预认证中手动指定etype为RC4_MD4加密时,可以看到KDC也能支持这种加密方式,并做了正确的响应。
RC4_MD4安全风险
在阅读Windows对于RC4_MD4相关的资料及实现后,可以发现Windows并没有按照标准的RC4算法原理来实现加密过程,而是对其进行了结合实际利用的一些改造,比如针对Kerberos加密过程中,如果使用了RC4_MD4加密算法,则Windows对其的实现存在以下几种安全风险:
RC4_MD4加密key是16字节,但实际使用只有前8字节;
key在加密过程中没有进行变换处理,对于相同的加密key,生成的key_stream一直都是相同的;
kerberos加密不同部分使用的都是相同的key;
RC4_MD4不存在消息完整性检查,无法防止消息篡改;
RC4_MD4加密算法生成的session_key为16字节,但是只有前5个字节是随机数,后11字节填充0xab;
在Windows源码中我们能看出一些其实现上的缺陷,如下图的8字节的加密Key以及生成session_key过程中的5字节随机11字节填充。
RC4算法本身相对比较简单,重点在于密钥流的生成,因此我们对于Windows中的实现也主要关心其密钥流的生成部分,由于篇幅原因本文在此处不展开讲,大家对算法原理感兴趣的可以查询资料详细了解。
DER编码
Kerberos的数据包采用了DER编码对ASN.1格式的数据包进行序列化,DER编码是一种TLV编码系统,所以在实际的数据包中,在每一个字段之前都会有一些固定的“元数据”来用来描述数据的标记,长度等信息。
以PA-ENC-TS-ENC为例,上图标识PA-ENC-TS-ENC经过DER编码之后的格式,其中黄色部分表示实际数据,绿色部分表示DER编码产生的“标记数据”,DER编码中部分字节对应的含义如下:
30 -> Sequence tag
1A – (int) 26 (length of entire structure)
A0 – 1st element tag
11 – element length
18 – Generalize time tag
0F – (int) value length (15)
A1 – 2nd element tag
05 – (int) element length
02 – INTEGER type tag
03 – (int) value length
CVE-2022-33647
前面提到CVE-2022-33647漏洞为场景为一种中间人攻击的漏洞,在此场景中,攻击者可以劫持进出KDC的流量,因AS-REQ的etype字段不受保护可以随意修改,因此可以直接修改etype字段为仅支持 RC4_MD4加密,然后将其发送到 KDC。
Kerberos认证过程中,一般会向 KDC 发送一个不存在预身份验证时间戳的请求。如果该账户未设置不需要预身份验证,KDC 就会向客户端返回 一个错误响应
(KDC_ERR_PREAUTH_REQUIRED)。
在该错误响应中KDC 还在PA-ETYPE-INFO2预认证数据结构中发送可接受的加密类型列表。此列表包含密钥派生密码的附加信息,如 AES 密钥的盐。如果我们通过第一步使KDC仅支持 RC4_MD4 ,那么客户端将使用RC4_MD4来生成预身份验证的时间戳。
当 KDC 收到AS-REQ的时间戳后,将使用 RC4_MD4 算法对其进行验证,并返回使用RC4_MD4密钥加密的 AS-REP部分,该密钥与加密时间戳使用相同的密钥进行加密。在上面我们已经提到Windows在实现RC4_MD4 算法的一些脆弱性,用于加密时间戳的密钥流必须与用于加密session_key的的密钥流相同,因此,我们可以通过已知的部分明文来从时间戳中重新异或恢复密钥流,并使用恢复的密钥流来解密EncASRepPart部分响应内容。
从EncASRepPart定义可以看到session_key是整个结构的第一个字段,将这个结构进行DER编码之后可以发现session_key字段前4个字节与PA-ENC-TS-ENC中的“元数据”正好存在重叠,而前面我们说过,在RC4_MD4加密中session_key只有前5个字节是随机数,后11个字节填充0xAB。PA-ENC-TS-ENC中元数据是固定的,密文我们可以通过抓包利用固定的偏移计算得到,有了这两个条件我们就可以计算出加密使用的密钥流(key_stream),由于是同一个用户密码,RC4_MD4加密使用的密钥流都是固定的,我们可以通过密钥流来还原出session_key前4个字节。
在获取session_key前4个字节之后,还剩下一个字节是未知的,这时候有两种攻击方式破解这一个字节,一种是在线爆破,利用TGT和session_key申请服务票据(TGS_REQ),这时候session_key有256种可能,最多发送256次TGS_REQ可以破解出session_key。另外一种攻击方式是离线爆破,我们可以抓一个TGS响应包(TGS_REP),由于TGS_REP中encpart部分是由上一轮AS_REP返回的session_key进行加密的,我们可以利用这部分对session_key进行爆破,这种离线爆破的方式更加高效。
上图清晰的描述了该攻击的利用过程,可以看出是一个典型的中间人攻击。对于CVE-2022-33647的漏洞分析到这基本就已经结束,这里留一个问题,Kerberos Relay是不是终于迎来了春天呢,大家可以基于此漏洞进行深入分析。
CVE-2022-33679
CVE-2022-33679实现了另一种对RC4_MD4加密算法的攻击方式,这种方式需要域内存在一个设置了不需要预认证的用户,在这种条件下,在不需要用户的密码的情况下就能通过AS_REQ获取用户的TGT,并且在加密方式中指定RC4_MD4时,AS_REP的encpart就会用RC4_MD4加密。
上面的攻击方式中是利用时间戳来解密密钥流,再通过TGS_REQ去爆破session_key,但是在现在的场景中我们无法得到加密后的时间戳,所以也没办法通过时间戳来解密密钥流,但是这一次我们有AS_REP,可以利用AS_REP中的EncASRepPart部分来解密密钥流。
上图是移除usec之后PA-ENC-TS-ENC和EncASRepPart进行DER编码之后的对比,EncASRepPart中已知的有21个字节可以通过这21个字节明文以及密文来计算出加密这部分的密钥流,但是只有21个字节的密钥流是无法解密出22字节以后的session_key的,那么该怎么得到更长的密钥流呢,答案就是AS_REQ,这一部分利用了几个小trick。
首先在PA-ENC-TS-ENC中timestamp是YYYYMMDDHHmmssZ的ASCII字符串来表示的,KDC在解析字符串时会根据格式自适应解析,所以在这个字符串后门加一个NUL字符也是可以接受的。
添加一个NUL字符之后可以发现在第22个字节与session_key发生了重叠,这个时候我们就可以对密钥流的第22个字节进行爆破,利用22字节长度的的密钥流对PA-ENC-TS-ENC进行加密发送给KDC,如果密钥流错误的话,KDC就无法解密出时间戳,返回报错信息KRB_ERR_GENERIC,如果密钥流正确,则KDC不会有报错,通过这种区别就可以还原出EncASRepPart的第22个字节,也就是session_key的第1个字节,但是session_key还有4个字节是未知的,有2^32种可能,通过爆破显然是不现实的,所以这里又利用了另外一个trick。
short form & long form
在DER编码中,长度编码有两种方式: 短型长度表示法(short form)和长型长度表示法(long form),短型长度表示法是在长度小于127(0b01111111)的情况,用这个字节本身表示长度,短型长度表示法中字节的最高位总是0,例如上图表示长度的0x14,就表示数据长度为0x14即20个字节。如果用长型长度表示法的话首字节的低7位标识的是存储长度的字节数,并且长度的值用大端序存储,比如0x14用长型长度表示法0x81 0x14表示,0x81的二进制形式是0b10000001,最高位是1说明是长型长度表示法,后7位为1,表示存储长度的字节数为1字节,就是后面的0x14。以此类推可以通过0x82 0x00 0x14, 0x83 0x00 0x00 0x14 来表示长度0x14。
通过修改PA-ENC-TS-ENC长度表示法可以合法的修改PA-ENC-TS-ENC的长度,通过不同的长度就能爆破出密钥流剩余的4字节从而解密session_key的剩余4字节。整个过程最多需要爆破5*2^8也就是1280次,在实际攻击中也是非常可行的。
CVE-2022-33679将传统的AS-REPRoasting提升到了一个新的高度,并为AD域的攻击提供了一个更为隐蔽的攻击及权限维持方式。
防御检测
根据微软官方指导在域控安装相应的安全补丁,补丁安装成功后将默认禁用RC4_MD4加密算法,安装此补丁前请详细确认RC4_MD4的禁用不会对现有业务造成影响,避免造成大规模的业务故障,官方补丁链接参照以下官网链接:
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-33679
中安网星智域目录安全管理平台默认支持降级加密检测,可以识别异常加密降级类攻击,同时我们针对此漏洞单独更新针对性的检测规则,对于部署了智域目录安全管理平台的客户,可以更新规则进行升级。
参考文章
https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html
https://github.com/Amulab/CVE-2022-33679