def parse(cls, bytes): (response, resp_type, hi_resp_type, reserved1, reserved2, timestamp, challenge_from_client, reserved) = ntlmv2response_header.unpack_from(bytes) if resp_type != 0x01 or hi_resp_type != 0x01: raise 'Not a valid NTLMv2Response' target_info = TargetInfo() target_info.unpack(bytes[ntlmv2response_header.size:]) return cls(challenge_from_client, timestamp, target_info)
def test_parse_challenge_message(self): test_target_info = TargetInfo() test_target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ "Domain".encode('utf-16-le') test_target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ "Server".encode('utf-16-le') test_challenge_string = base64.b64encode( b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" b"\x02\x00\x00\x00\x03\x00\x0c\x00" b"\x38\x00\x00\x00\x33\x82\x8a\xe2" b"\x01\x23\x45\x67\x89\xab\xcd\xef" b"\x00\x00\x00\x00\x00\x00\x00\x00" b"\x24\x00\x24\x00\x44\x00\x00\x00" b"\x06\x00\x70\x17\x00\x00\x00\x0f" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x02\x00\x0c\x00" b"\x44\x00\x6f\x00\x6d\x00\x61\x00" b"\x69\x00\x6e\x00\x01\x00\x0c\x00" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x00\x00\x00\x00" ) test_ntlm_context = Ntlm() test_ntlm_context.parse_challenge_message(test_challenge_string) expected_message_type = MessageTypes.NTLM_CHALLENGE expected_negotiate_flags = 3800728115 expected_server_challenge = b"\x01\x23\x45\x67\x89\xab\xcd\xef" expected_signature = NTLM_SIGNATURE expected_target_info = test_target_info.pack() expected_target_name = None expected_version = 1080863910962135046 actual = test_ntlm_context.challenge_message actual_message_type = actual.message_type actual_negotiate_flags = actual.negotiate_flags actual_server_challenge = actual.server_challenge actual_signature = actual.signature actual_target_info = actual.target_info.pack() actual_target_name = actual.target_name actual_version = actual.version assert actual_message_type == expected_message_type assert actual_negotiate_flags == expected_negotiate_flags assert actual_server_challenge == expected_server_challenge assert actual_signature == expected_signature assert actual_target_info == expected_target_info assert actual_target_name == expected_target_name assert actual_version == expected_version
def test_del_item(self): target_info = TargetInfo() target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" del target_info[AvId.MSV_AV_NB_DOMAIN_NAME] # Contains the len and id of MSV_AV_NB_COMPUTER_NAME and the EOL as we # have remove MSV_AV_NB_DOMAIN_NAME expected = b"\x01\x00\x0c\x00\x53\x00\x65\x00" \ b"\x72\x00\x76\x00\x65\x00\x72\x00" \ b"\x00\x00\x00\x00" actual = target_info.pack() assert actual == expected
def test_lm_v2_response_with_server_target_info_timestamp(self): test_target_info = TargetInfo() test_target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" test_target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" test_target_info[AvId.MSV_AV_TIMESTAMP] = b"\x00" * 8 test_challenge_message = ChallengeMessage( b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" b"\x02\x00\x00\x00\x03\x00\x0c\x00" b"\x38\x00\x00\x00\x33\x82\x8a\xe2" b"\x01\x23\x45\x67\x89\xab\xcd\xef" b"\x00\x00\x00\x00\x00\x00\x00\x00" b"\x24\x00\x24\x00\x44\x00\x00\x00" b"\x06\x00\x70\x17\x00\x00\x00\x0f" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x02\x00\x0c\x00" b"\x44\x00\x6f\x00\x6d\x00\x61\x00" b"\x69\x00\x6e\x00\x01\x00\x0c\x00" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x00\x00\x00\x00" ) test_challenge_message.target_info = test_target_info # Not in MS-NLMP, using expected value expected = b"\x00" * 24 actual = ComputeResponse("User", "Password", "Domain", test_challenge_message, 3).get_lm_challenge_response() assert actual == expected
def test_get_NTLMv2_response(self): # 4.2.4.2.2 - NTLMv2 Response server_challenge = b"\x01\x23\x45\x67\x89\xab\xcd\xef" client_challenge = b"\xaa" * 8 test_target_info = TargetInfo() test_target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" test_target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" expected_response = b"\x68\xcd\x0a\xb8\x51\xe5\x1c\x96" \ b"\xaa\xbc\x92\x7b\xeb\xef\x6a\x1c" \ b"\x01\x01\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" \ b"\x00\x00\x00\x00\x02\x00\x0c\x00" \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00" \ b"\x69\x00\x6e\x00\x01\x00\x0c\x00" \ b"\x53\x00\x65\x00\x72\x00\x76\x00" \ b"\x65\x00\x72\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00" expected_key = b"\x8d\xe4\x0c\xca\xdb\xc1\x4a\x82" \ b"\xf1\x5c\xb0\xad\x0d\xe9\x5c\xa3" actual_response, actual_key = \ ComputeResponse._get_NTLMv2_response("User", "Password", "Domain", server_challenge, client_challenge, b"\x00" * 8, test_target_info) assert actual_response == expected_response assert actual_key == expected_key
def test_lm_v2_response_with_no_target_info_timestamp(self, monkeypatch): monkeypatch.setattr('os.urandom', lambda s: b"\xaa" * 8) test_target_info = TargetInfo() test_target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" test_target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" test_challenge_message = ChallengeMessage( b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" b"\x02\x00\x00\x00\x03\x00\x0c\x00" b"\x38\x00\x00\x00\x33\x82\x8a\xe2" b"\x01\x23\x45\x67\x89\xab\xcd\xef" b"\x00\x00\x00\x00\x00\x00\x00\x00" b"\x24\x00\x24\x00\x44\x00\x00\x00" b"\x06\x00\x70\x17\x00\x00\x00\x0f" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x02\x00\x0c\x00" b"\x44\x00\x6f\x00\x6d\x00\x61\x00" b"\x69\x00\x6e\x00\x01\x00\x0c\x00" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x00\x00\x00\x00" ) test_challenge_message.target_info = test_target_info expected = b"\x86\xc3\x50\x97\xac\x9c\xec\x10" \ b"\x25\x54\x76\x4a\x57\xcc\xcc\x19" \ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" actual = ComputeResponse("User", "Password", "Domain", test_challenge_message, 3).get_lm_challenge_response() assert actual == expected
def test_challenge_message_with_target_name(self): # Same as the test above but with the flags modified to show it has the # target name for coverage test_target_info = TargetInfo() test_target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" test_target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" expected_message_type = MessageTypes.NTLM_CHALLENGE expected_negotiate_flags = 3800728119 expected_server_challenge = b"\x01\x23\x45\x67\x89\xab\xcd\xef" expected_signature = NTLM_SIGNATURE expected_target_info = test_target_info.pack() expected_target_name = "Server".encode('utf-16-le') expected_version = 1080863910962135046 challenge_msg = b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" \ b"\x02\x00\x00\x00\x0c\x00\x0c\x00" \ b"\x38\x00\x00\x00\x37\x82\x8a\xe2" \ b"\x01\x23\x45\x67\x89\xab\xcd\xef" \ b"\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\x24\x00\x24\x00\x44\x00\x00\x00" \ b"\x06\x00\x70\x17\x00\x00\x00\x0f" \ b"\x53\x00\x65\x00\x72\x00\x76\x00" \ b"\x65\x00\x72\x00\x02\x00\x0c\x00" \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00" \ b"\x69\x00\x6e\x00\x01\x00\x0c\x00" \ b"\x53\x00\x65\x00\x72\x00\x76\x00" \ b"\x65\x00\x72\x00\x00\x00\x00\x00" actual = ChallengeMessage(challenge_msg) actual_message_type = actual.message_type actual_negotiate_flags = actual.negotiate_flags actual_server_challenge = actual.server_challenge actual_signature = actual.signature actual_target_info = actual.target_info.pack() actual_target_name = actual.target_name actual_version = actual.version assert actual_message_type == expected_message_type assert actual_negotiate_flags == expected_negotiate_flags assert actual_server_challenge == expected_server_challenge assert actual_signature == expected_signature assert actual_target_info == expected_target_info assert actual_target_name == expected_target_name assert actual_version == expected_version
def test_nt_v2_response_with_timestamp_av_pair(self, monkeypatch): monkeypatch.setattr('os.urandom', lambda s: b"\xaa" * 8) test_target_info = TargetInfo() test_target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" test_target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" test_target_info[AvId.MSV_AV_TIMESTAMP] = b"\x00" * 8 test_challenge_message = ChallengeMessage( b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" b"\x02\x00\x00\x00\x03\x00\x0c\x00" b"\x38\x00\x00\x00\x33\x82\x8a\xe2" b"\x01\x23\x45\x67\x89\xab\xcd\xef" b"\x00\x00\x00\x00\x00\x00\x00\x00" b"\x24\x00\x24\x00\x44\x00\x00\x00" b"\x06\x00\x70\x17\x00\x00\x00\x0f" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x02\x00\x0c\x00" b"\x44\x00\x6f\x00\x6d\x00\x61\x00" b"\x69\x00\x6e\x00\x01\x00\x0c\x00" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x00\x00\x00\x00" ) test_challenge_message.target_info = test_target_info test_lmv2_response = b"\x86\xc3\x50\x97\xac\x9c\xec\x10" \ b"\x25\x54\x76\x4a\x57\xcc\xcc\x19" \ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" expected_response = b"\x5d\xeb\xf3\x87\x1c\x28\x94\xb8" \ b"\x1f\x16\x42\x81\xed\xbf\x0b\xff" \ b"\x01\x01\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" \ b"\x00\x00\x00\x00\x02\x00\x0c\x00" \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00" \ b"\x69\x00\x6e\x00\x01\x00\x0c\x00" \ b"\x53\x00\x65\x00\x72\x00\x76\x00" \ b"\x65\x00\x72\x00\x07\x00\x08\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\x06\x00\x04\x00\x02\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00" expected_exchange_key = b"\x9b\x37\x06\x8f\x99\x7a\x06\x5f" \ b"\xe9\xc7\x20\x63\x32\x88\xd4\x8f" expected_target_info = test_target_info expected_target_info[AvId.MSV_AV_FLAGS] = \ struct.pack("<L", AvFlags.MIC_PROVIDED) comp_response = ComputeResponse("User", "Password", "Domain", test_challenge_message, 3) actual_response, actual_exchange_key, actual_target_info = \ comp_response.get_nt_challenge_response(test_lmv2_response, None) assert actual_response == expected_response assert actual_exchange_key == expected_exchange_key assert actual_target_info == expected_target_info
def test_nt_v2_response_no_target_info(self, monkeypatch): monkeypatch.setattr('os.urandom', lambda s: b"\xaa" * 8) monkeypatch.setattr('ntlm_auth.compute_response.get_windows_timestamp', lambda: b"\x00" * 8) test_challenge_message = ChallengeMessage( b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" b"\x02\x00\x00\x00\x03\x00\x0c\x00" b"\x38\x00\x00\x00\x33\x82\x8a\xe2" b"\x01\x23\x45\x67\x89\xab\xcd\xef" b"\x00\x00\x00\x00\x00\x00\x00\x00" b"\x24\x00\x24\x00\x44\x00\x00\x00" b"\x06\x00\x70\x17\x00\x00\x00\x0f" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x02\x00\x0c\x00" b"\x44\x00\x6f\x00\x6d\x00\x61\x00" b"\x69\x00\x6e\x00\x01\x00\x0c\x00" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x00\x00\x00\x00" ) test_challenge_message.target_info = None test_lmv2_response = b"\x86\xc3\x50\x97\xac\x9c\xec\x10" \ b"\x25\x54\x76\x4a\x57\xcc\xcc\x19" \ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" expected_response = b"\x39\x56\xf2\xe5\x69\xd9\xaf\xa3" \ b"\xac\x2d\x4f\x36\x7d\x38\xb9\xc5" \ b"\x01\x01\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" \ b"\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00" expected_exchange_key = b"\xe3\x35\x1f\x5b\xe0\xa0\x2b\xc2" \ b"\xee\xb8\x76\x52\xf7\xe0\x77\x75" expected_target_info = TargetInfo() comp_response = ComputeResponse("User", "Password", "Domain", test_challenge_message, 3) actual_response, actual_exchange_key, actual_target_info = \ comp_response.get_nt_challenge_response(test_lmv2_response, None) assert actual_response == expected_response assert actual_exchange_key == expected_exchange_key assert actual_target_info.pack() == expected_target_info.pack()
def test_add_item(self): target_info = TargetInfo() target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" expected = b"\x02\x00\x0c\x00\x44\x00\x6f\x00" \ b"\x6d\x00\x61\x00\x69\x00\x6e\x00" \ b"\x01\x00\x0c\x00\x53\x00\x65\x00" \ b"\x72\x00\x76\x00\x65\x00\x72\x00" \ b"\x03\x00\x0c\x00\x53\x00\x65\x00" \ b"\x72\x00\x76\x00\x65\x00\x72\x00" \ b"\x00\x00\x00\x00" target_info[AvId.MSV_AV_DNS_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" actual = target_info.pack() assert actual == expected
def test_nt_v2_response(self, monkeypatch): monkeypatch.setattr('os.urandom', lambda s: b"\xaa" * 8) monkeypatch.setattr('ntlm_auth.compute_response.get_windows_timestamp', lambda: b"\x00" * 8) test_target_info = TargetInfo() test_target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" test_target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" test_challenge_message = ChallengeMessage( b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" b"\x02\x00\x00\x00\x03\x00\x0c\x00" b"\x38\x00\x00\x00\x33\x82\x8a\xe2" b"\x01\x23\x45\x67\x89\xab\xcd\xef" b"\x00\x00\x00\x00\x00\x00\x00\x00" b"\x24\x00\x24\x00\x44\x00\x00\x00" b"\x06\x00\x70\x17\x00\x00\x00\x0f" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x02\x00\x0c\x00" b"\x44\x00\x6f\x00\x6d\x00\x61\x00" b"\x69\x00\x6e\x00\x01\x00\x0c\x00" b"\x53\x00\x65\x00\x72\x00\x76\x00" b"\x65\x00\x72\x00\x00\x00\x00\x00" ) test_challenge_message.target_info = test_target_info test_lmv2_response = b"\x86\xc3\x50\x97\xac\x9c\xec\x10" \ b"\x25\x54\x76\x4a\x57\xcc\xcc\x19" \ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" expected_response = b"\x68\xcd\x0a\xb8\x51\xe5\x1c\x96" \ b"\xaa\xbc\x92\x7b\xeb\xef\x6a\x1c" \ b"\x01\x01\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" \ b"\x00\x00\x00\x00\x02\x00\x0c\x00" \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00" \ b"\x69\x00\x6e\x00\x01\x00\x0c\x00" \ b"\x53\x00\x65\x00\x72\x00\x76\x00" \ b"\x65\x00\x72\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00" expected_exchange_key = b"\x8d\xe4\x0c\xca\xdb\xc1\x4a\x82" \ b"\xf1\x5c\xb0\xad\x0d\xe9\x5c\xa3" expected_target_info = test_target_info comp_response = ComputeResponse("User", "Password", "Domain", test_challenge_message, 3) actual_response, actual_exchange_key, actual_target_info = \ comp_response.get_nt_challenge_response(test_lmv2_response, None) assert actual_response == expected_response assert actual_exchange_key == expected_exchange_key assert actual_target_info == expected_target_info
def test_get_item(self): target_info = TargetInfo() target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" expected_value = b"\x44\x00\x6f\00\x6d\x00\x61\x00" \ b"\x69\x00\x6e\x00" expected_length = len(expected_value) actual = target_info[AvId.MSV_AV_NB_DOMAIN_NAME] assert len(actual) == expected_length assert actual == expected_value
def test_nt_v2_temp_response(self): # 4.2.4.1.3 - temp test_target_info = TargetInfo() test_target_info[AvId.MSV_AV_NB_DOMAIN_NAME] = \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00" test_target_info[AvId.MSV_AV_NB_COMPUTER_NAME] = \ b"\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00" expected = b"\x01\x01\x00\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00\x00\x00\x00\x00" \ b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" \ b"\x00\x00\x00\x00\x02\x00\x0c\x00" \ b"\x44\x00\x6f\x00\x6d\x00\x61\x00" \ b"\x69\x00\x6e\x00\x01\x00\x0c\x00" \ b"\x53\x00\x65\x00\x72\x00\x76\x00" \ b"\x65\x00\x72\x00\x00\x00\x00\x00" \ b"\x00\x00\x00\x00" actual = ComputeResponse._get_NTLMv2_temp(b"\x00" * 8, b"\xaa" * 8, test_target_info) assert actual == expected