zerologon packet analysis
2022-07-17
Background
Vulnerabilities are discovered on a daily basis but there are a couple that stand out due to their severity level and how easy it is to execute. Since one of the best ways to learn is to actually do the thing instead of reading an article or blog post about it, thought I'd experiment solo to try and understand how these vulnerabilities and exploits work. The importance here is to leave no stone unturned, learn everything and anything about them no matter how indepth and 'difficult' it gets. From what I remember, ZeroLogon was a vulnerability found by the organization Secura although I have no idea what that org. does. It's a vulnerability that can go from no account to domain level access somehow, and thus relates to AD. Active Directory has become a stable in information security lately, so soon they'll include them in syllabus of university classrooms and degrees for cybersecurity is what I believe... Perfect chance for an indepth look at it.Initial Research
Requirements: High level understanding of ZeroLogon NetrServer[ReqChallenge, Authenticate3, SetPassword2] Packet Analysis Secura PoC teardownThe best method of understanding how this vulnerability works is not just reading a whitepaper released by the guys who found it, but to really understand the inner workings of all the components and be able to pull it off myself. This is what the requirements enable us to do; I'd like to note that initial research has been done via a TryHackMe room named 'ZeroLogon' under the Cyber Defense pathway. TryHackMe is a great way to learn that 'x' information exists but not the best method to learn it, which is what this project hopefully will do.
TryHackMe\Cyber Defense\ZeroLogon\Secura WhitepaperA python PoC is also one of the requirements which will be a PoC provided by Secura. I'm not a programmer nor do I care to learn programming too indepth, but one of the foundations of information security is to be able to read code! Which is why review of a python PoC is perfect in this instance.
Secura Python PoC
Secura ZeroLogon Whitepaper
MS-NRPC & ZeroLogon
The vulnerability exists due to poor implementation of cryptography regarding the use of a hard-coded IV. Typically if the IV is hard-coded or can be guessed then that reveals an attack surface for the bad guys, which is exactly what this case is. MS-NRPC is a protocol that authenticates user & machine accounts for AD (Active Directory), so authentication between client and user is important. It's important to note that there is no limit to account logon attempts here because we try to log into a machine account which has a really long password and thus the guys at Microsoft thought noone would bruteforce it anyways so why put a limit to it.
# ---[ aes_cfb8.py ]---
iv = b"\x00" * 16
def encrypt(bs: bytes, key: bytes) -> bytes:
cipher = AES.new(key, AES.MODE_ECB)
res = list(iv + bs)
iv_len = len(iv)
for i in range(len(bs)):
res[iv_len + i] = cipher.encrypt(
bytes(res[i:i+iv_len]))[0] ^ res[iv_len + i]
return bytes(res[iv_len:])
gh\kurenaif\aes_cfb8wikipedia\aes_cfb8
The encryption algorithm used by Microsoft for MS-NRPC is AES-CFB8 which is not a bad encryption algorithm by any means. But if you notice the first line, the IV (Init. Vector) is hardcoded and all set to 0's, exactly done by Microsoft.
Steps: NetrServerReqChallenge [Client -> Server] Server Challenge [Server -> Client] NetrServerAuthenticate3 [Client -> Server] Compute+Compare Values [Server -> Client]The steps provided are those that will test for whether ZeroLogon is exploitable or not in your case. We don't have a full kill chain as this only checks that the vulnerability exists, not tries to change any passwords and log in. That will be shown later. Steps 3 & 4 is where the loop happens and on average 1/256 chance you will get both client computed and server computed values to be the same, thus authenticating you to the domain. We'll first look at both the Netr Auth and Challenge functions to understand what really is going on, this will also help in understanding AD - perfect for OSCP down the road I hope?
NetrServerReqChallenge
NTSTATUS NetrServerReqChallenge( [in, unique, string] LOGONSRV_HANDLE PrimaryName, [in, string] wchar_t* ComputerName, [in] PNETLOGON_CREDENTIAL ClientChallenge, [out] PNETLOGON_CREDENTIAL ServerChallenge );Similar to many login methodologies systems exist to check whether the client is who they say they are, also confirming they hold the correct password. The function above tests for this by sending the parameters labeled [in]: PrimaryName, ComputerName and ClientChallenge. The primary name is the handle used during binding (mentioned later), the computer name is the name of the client computer (spoofed name in this case DC01), and finally the challenge we input is all zero's.
Wireshark ServerReqChallenge Client

Wireshark ServerReqChallenge Server

Sidenote: CVE-2019-1424 [Netlogon MiTM]
After comm' explained above, the same author who discovered ZeroLogon also had discovered another vulnerability (less harsh) prior to Zerologon, this is CVE 2019-1424 which is gaining access to windows systems via Man-in-The-Middle attack. This CVE is not the importance of this project, but I looked into it a bit and this occurs when the attacker sends a RST packet right after the session has been authenticated and is starting to take shape. This causes comm' to take place over SMB instead of EPM and Netlogon default port, resulting in dropping of encryption between the client and server. Attackers could modify comm' from now on even though there is an authenticator field in the first message it is not used in concurrent messages so leaving it alone is sufficient.CVE-2019-1424 by Tom Tervoort, Secura
Sidenote: CVE-2019-1424 [Netlogon MiTM]
NTSTATUS NetrServerAuthenticate3( [in, unique, string] LOGONSRV_HANDLE PrimaryName, [in, string] wchar_t* AccountName, [in] NETLOGON_SECURE_CHANNEL_TYPE SecureChannelType, [in, string] wchar_t* ComputerName, [in] PNETLOGON_CREDENTIAL ClientCredential, [out] PNETLOGON_CREDENTIAL ServerCredential, [in, out] ULONG * NegotiateFlags, [out] ULONG * AccountRid );Quickly going over through the parameters of this authenticate function, similar to the previous request challenge function we have PrimaryName, ComputerName. AccountName refers to the account we're trying to log into, SecureChannelType is the channel type we use (e.g Backup domain controller). Both client and server credentials are computed values that take in the previous challenges that were generated in the previous function (NetrServerReqChallenge). The negotiate flags contain flags that set encryption types, supported function calls and more things that can be done. AccountRid is the identifier the account belongs in, think somewhat similar to Unix groups and users, it is also unique.

