oooo   o8o
                                                                            `888   `"'
                                                                   .oooo.    888  oooo      ooo. .oo.  .oo.
                                                                  `P  )88b   888  `888      `888P"Y88bP"Y88b
                                                                   .oP"888   888   888       888   888   888
                                                                  d8(  888   888   888  .o.  888   888   888
                                                                  `Y888""8o o888o o888o Y8P o888o o888o o888o

0x11 ZeroLogon Packet Analysis

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 teardown
			

The 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 Whitepaper

A 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_cfb8
wikipedia\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 Client
The server needs only to respond with their own 8-byte challenge nonce, the return value for this function is either a success or I suppose a failure. This does not mean we have succeeded in the vulnerability yet, but only passed the first check of client and server challenge to setup a session between ourselves and the server. It's interesting to see how easy it is to spoof the user computer name and the server just accepting it as is without any sort of verification! Wireshark ServerReqChallenge Server
Wireshark ServerReqChallenge Server
To go a little more in depth in a successful client-server connection attempt, the challenges are used to generate a session key via a function that takes both the 'secret key' (client password) and the two challenges. This session key is then used to generate both the client and server credentials, which if they are equal that means that the client has input the correct password for the account login. Unfortunately I can't seem to figure out where this comm' takes place within wireshark as the next RPC is NetrServerAuthenticate3 and both have different client-server challenges but result in a correct login. Screenshots for that communication is below.

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

NetrServerAuthenticate3


		 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.

Screenshot shows all the parameters labeled [in]; important note here is that encryption after authentication is set inside the negotiate flags so unsetting that bit allows downgrade to SMB resulting in no encryption and possibility of man-in-the-middle attacks. ComputeNetlogonCredential is a function that uses the previously generated challenges to create credentials, client-side we use all zero's so the generated credential will be all zero's. Server-side there is a possibility in ratio of 1-256 that our key uses the same key, resulting in proper authentication. This can simply be prevented by disallowing continues attempts at logging in but the chances are still quite high, so removal of hard coded IV is necessary!
Above is an example of successful authentication due to our return code of succes. Via wireshark we can search for this to find where we authenticate properly, so during forensics or a CTF searching for this is easy.