# Impacket - Collection of Python classes for working with network protocols. # # Copyright (C) 2023 Fortra. All rights reserved. # # This software is provided under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # from __future__ import print_function import unittest import struct from six import b from impacket import ntlm from impacket.structure import hexdump class NTLMTests(unittest.TestCase): def setUp(self): # Turn test case mode on ntlm.TEST_CASE = True self.user = "User" self.domain = "Domain" self.password = "Password" self.serverName = "Server" self.workstationName = "COMPUTER" self.randomSessionKey = b("U"*16) self.time = b('\x00'*8) self.clientChallenge = b("\xaa"*8) self.serverChallenge = b("\x01\x23\x45\x67\x89\xab\xcd\xef") self.flags = ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH | ntlm.NTLMSSP_NEGOTIATE_56 | ntlm.NTLMSSP_NEGOTIATE_128 | ntlm.NTLMSSP_NEGOTIATE_VERSION | 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 self.seqNum = 0 self.nonce = b('\x00'*16) self.plaintext = 'Plaintext'.encode('utf-16le') print("Flags") hexdump(struct.pack('<\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.assertEqual(sealedMsg, bytearray(b'V\xfe\x04\xd8a\xf91\x9a\xf0\xd7#\x8a.;ME\x7f\xb8')) print("\n") hexdump(signature.getData()) self.assertEqual(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('')) 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.assertEqual(clientSealingKey, bytearray(b'Y\xf6\x00\x97<\xc4\x96\n%H\n|\x19nLX')) print("\n") print("SIGNKEY()") hexdump(clientSigningKey) self.assertEqual(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.assertEqual(sealedMsg, bytearray(b'T\xe5\x01e\xbf\x196\xdc\x99` \xc1\x81\x1b\x0f\x06\xfb_')) print("\n") print("Signature") hexdump(signature.getData()) self.assertEqual(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 __pack_and_parse(self, message, expected): data = message.getData() hexdump(data) self.assertEqual(data, expected) parsed = ntlm.NTLMAuthNegotiate() parsed.fromString(data) return parsed def test_refactor_negotiate_message(self): print('#### Pack and parse, without version') negoMsgToPack = ntlm.NTLMAuthNegotiate() negoMsgParsed = self.__pack_and_parse(negoMsgToPack, bytearray( b'NTLMSSP\x00\x01\x00\x00\x001\x02\x00`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' )) self.assertEqual(negoMsgParsed['flags'] & ntlm.NTLMSSP_NEGOTIATE_VERSION, 0) self.assertEqual(negoMsgParsed['os_version'], '') print('#### Pack and parse, with version') major, minor, build = 10, 0, 19041 version = ntlm.VERSION() version['ProductMajorVersion'], version['ProductMinorVersion'], version['ProductBuild'] = major, minor, build negoMsgToPack = ntlm.NTLMAuthNegotiate() negoMsgToPack['os_version'] = version negoMsgParsed = self.__pack_and_parse(negoMsgToPack, bytearray( b'NTLMSSP\x00\x01\x00\x00\x001\x02\x00b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b'\x0a\x00aJ\x00\x00\x00\x0f' )) self.assertEqual(negoMsgParsed['flags'] & ntlm.NTLMSSP_NEGOTIATE_VERSION, ntlm.NTLMSSP_NEGOTIATE_VERSION) self.assertEqual(negoMsgParsed['os_version']['ProductMajorVersion'], major) self.assertEqual(negoMsgParsed['os_version']['ProductMinorVersion'], minor) self.assertEqual(negoMsgParsed['os_version']['ProductBuild'], build) print('#### Try to set the NTLMSSP_NEGOTIATE_VERSION flag without specifying os_version') negoMsgToPack = ntlm.NTLMAuthNegotiate() negoMsgToPack['flags'] |= ntlm.NTLMSSP_NEGOTIATE_VERSION self.assertRaises(Exception, negoMsgToPack.getData) if __name__ == '__main__': unittest.main(verbosity=1)