Пример #1
0
    def test_create_authenticate_message_without_security(
            self, random_function, version_function, session_key_function,
            timestamp_function):
        test_challenge_string = base64.b64encode(ntlmv2_challenge_message)
        test_ntlm_context = Ntlm()
        test_ntlm_context.create_negotiate_message(domain_name,
                                                   workstation_name)
        test_ntlm_context.parse_challenge_message(test_challenge_string)
        # Need to override the sign and seal flags so they don't return a security context
        test_ntlm_context.negotiate_flags -= NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN
        test_ntlm_context.negotiate_flags -= NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL

        # Need to override the flags in the challenge message to match the expectation, these flags are inconsequential and are done manualy for sanity
        test_ntlm_context.challenge_message.negotiate_flags -= NegotiateFlags.NTLMSSP_TARGET_TYPE_SERVER
        test_ntlm_context.challenge_message.negotiate_flags |= NegotiateFlags.NTLMSSP_REQUEST_TARGET

        expected_message = base64.b64encode(
            ntlmv2_authenticate_message).decode()

        actual_message = test_ntlm_context.create_authenticate_message(
            user_name, password, domain_name, "COMPUTER").decode()
        actual_session_security = test_ntlm_context.session_security

        assert actual_message == expected_message
        assert actual_session_security is None
Пример #2
0
    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
Пример #3
0
    def retry_with_ntlm_auth_legacy(self, auth_header_field, auth_header,
                                    response, auth_type, args):
        try:
            cert_hash = self._get_server_cert(response)
        except Exception:
            cert_hash = None

        context = Ntlm(ntlm_compatibility=self.ntlm_compatibility)

        # Consume the original response contents and release the connection for
        # later
        response.content
        response.raw.release_conn()

        # Create the negotiate request
        msg1_req = response.request.copy()
        msg1 = context.create_negotiate_message(self.domain)
        msg1_header = "%s %s" % (auth_type, msg1.decode('ascii'))
        msg1_req.headers[auth_header] = msg1_header

        # Send the negotiate request and receive the challenge message
        disable_stream_args = dict(args, stream=False)
        msg2_resp = response.connection.send(msg1_req, **disable_stream_args)
        msg2_resp.content
        msg2_resp.raw.release_conn()

        # Parse the challenge response in the ntlm_context
        msg2_header = msg2_resp.headers[auth_header_field]
        msg2 = msg2_header.replace(auth_type + ' ', '')
        context.parse_challenge_message(msg2)

        # Create the authenticate request
        msg3_req = msg2_resp.request.copy()

        msg3 = context.create_authenticate_message(
            self.username,
            self.password,
            self.domain,
            server_certificate_hash=cert_hash)
        msg3_header = auth_type + ' ' + msg3.decode('ascii')
        msg3_req.headers[auth_header] = msg3_header

        # Send the authenticate request
        final_response = msg2_resp.connection.send(msg3_req, **args)
        final_response.history.append(response)
        final_response.history.append(msg2_resp)

        return final_response
Пример #4
0
class NtlmContext(object):
    def __init__(self, username, password):
        if username is None:
            raise SMBAuthenticationError("The username must be set when using "
                                         "NTLM authentication")
        if password is None:
            raise SMBAuthenticationError("The password must be set when using "
                                         "NTLM authentication")

        # try and get the domain part from the username
        log.info("Setting up NTLM Security Context for user %s" % username)
        try:
            self.domain, self.username = username.split("\\", 1)
        except ValueError:
            self.username = username
            self.domain = ''
        self.password = password
        self.context = Ntlm()
        self.in_token = None

    def step(self):
        log.info("NTLM: Generating Negotiate message")
        msg1 = self.context.create_negotiate_message(self.domain)
        msg1 = base64.b64decode(msg1)
        log.debug("NTLM: Negotiate message: %s" % _bytes_to_hex(msg1))
        yield msg1

        log.info("NTLM: Parsing Challenge message")
        msg2 = base64.b64encode(self.in_token)
        log.debug("NTLM: Challenge message: %s" % _bytes_to_hex(self.in_token))
        self.context.parse_challenge_message(msg2)

        log.info("NTLM: Generating Authenticate message")
        msg3 = self.context.create_authenticate_message(
            user_name=self.username,
            password=self.password,
            domain_name=self.domain)
        yield base64.b64decode(msg3)

    def get_session_key(self):
        return self.context.authenticate_message.exported_session_key
Пример #5
0
    def test_parse_challenge_message(self):
        test_target_info = TargetInfo()
        test_target_info[
            TargetInfo.MSV_AV_NB_DOMAIN_NAME] = ntlmv2_netbios_domain_name
        test_target_info[
            TargetInfo.MSV_AV_NB_COMPUTER_NAME] = ntlmv2_netbios_server_name
        test_challenge_string = base64.b64encode(ntlmv2_challenge_message)
        test_ntlm_context = Ntlm()
        test_ntlm_context.parse_challenge_message(test_challenge_string)

        expected_message_type = MessageTypes.NTLM_CHALLENGE
        expected_negotiate_flags = ntlmv2_negotiate_flags
        expected_server_challenge = server_challenge
        expected_signature = NTLM_SIGNATURE
        expected_target_info = test_target_info.get_data()
        expected_target_name = None
        expected_version = struct.unpack(
            "<q", HexToByte('06 00 70 17 00 00 00 0f'))[0]

        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.get_data()
        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
Пример #6
0
class NtlmAuth(AuthBase):

    def __init__(self, domain, username, password, ntlm_compatibility):
        self.username = username
        self.domain = domain.upper()
        self.password = password
        self.context = Ntlm(ntlm_compatibility=ntlm_compatibility)

    def __call__(self, response):
        response.headers['Connection'] = 'Keep-Alive'
        response.register_hook('response', self.hook)
        return response

    def hook(self, response, **kwargs):
        if response.status_code == 401:
            return self.retry_with_ntlm_auth('www-authenticate',
                                             'Authorization', response,
                                             'NTLM', kwargs)
        else:
            return response

    def retry_with_ntlm_auth(self, auth_header_field, auth_header, response,
                             auth_type, args):
        try:
            cert_hash = self._get_server_cert(response)
        except Exception:
            cert_hash = None

        # Consume the original response contents and release the connection for
        # later
        response.content
        response.raw.release_conn()

        # Create the negotiate request
        msg1_req = response.request.copy()
        msg1 = self.context.create_negotiate_message(self.domain)
        msg1_header = "%s %s" % (auth_type, msg1.decode('ascii'))
        msg1_req.headers[auth_header] = msg1_header

        # Send the negotiate request and receive the challenge message
        disable_stream_args = dict(args, stream=False)
        msg2_resp = response.connection.send(msg1_req, **disable_stream_args)
        msg2_resp.content
        msg2_resp.raw.release_conn()

        # Parse the challenge response in the ntlm_context
        msg2_header = msg2_resp.headers[auth_header_field]
        msg2 = msg2_header.replace(auth_type + ' ', '')
        self.context.parse_challenge_message(msg2)

        # Create the authenticate request
        msg3_req = msg2_resp.request.copy()

        msg3 = self.context.create_authenticate_message(
            self.username, self.password, self.domain,
            server_certificate_hash=cert_hash
        )
        msg3_header = auth_type + ' ' + msg3.decode('ascii')
        msg3_req.headers[auth_header] = msg3_header

        # Send the authenticate request
        final_response = msg2_resp.connection.send(msg3_req, **args)
        final_response.history.append(response)
        final_response.history.append(msg2_resp)

        return final_response

    def _get_server_cert(self, response):
        if sys.version_info > (3, 0):
            socket = response.raw._fp.fp.raw._sock
        else:
            socket = response.raw._fp.fp._sock

        server_certificate = socket.getpeercert(True)
        hash_object = hashlib.sha256(server_certificate)
        server_certificate_hash = hash_object.hexdigest().upper()

        return server_certificate_hash
Пример #7
0
    def test_create_authenticate_message_without_security(self, monkeypatch):
        monkeypatch.setattr('os.urandom', lambda s: b"\xaa" * 8)
        monkeypatch.setattr('ntlm_auth.messages.get_version',
                            lambda s: b"\x05\x01\x28\x0A\x00\x00\x00\x0F")
        monkeypatch.setattr('ntlm_auth.messages.get_random_export_session_key',
                            lambda: b"\x55" * 16)
        monkeypatch.setattr('ntlm_auth.compute_response.get_windows_timestamp',
                            lambda: b"\x00" * 8)

        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.create_negotiate_message("Domain", "COMPUTER")
        test_ntlm_context.parse_challenge_message(test_challenge_string)
        # Need to override the sign and seal flags so they don't return a
        # security context
        test_ntlm_context.negotiate_flags -= \
            NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN
        test_ntlm_context.negotiate_flags -=\
            NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL

        # Need to override the flags in the challenge message to match the
        # expectation, these flags are inconsequential and are done manualy for
        # sanity
        test_ntlm_context.challenge_message.negotiate_flags -= \
            NegotiateFlags.NTLMSSP_TARGET_TYPE_SERVER
        test_ntlm_context.challenge_message.negotiate_flags |= \
            NegotiateFlags.NTLMSSP_REQUEST_TARGET

        expected_message = base64.b64encode(
            b"\x4e\x54\x4c\x4d\x53\x53\x50\x00"
            b"\x03\x00\x00\x00\x18\x00\x18\x00"
            b"\x6c\x00\x00\x00\x54\x00\x54\x00"
            b"\x84\x00\x00\x00\x0c\x00\x0c\x00"
            b"\x48\x00\x00\x00\x08\x00\x08\x00"
            b"\x54\x00\x00\x00\x10\x00\x10\x00"
            b"\x5c\x00\x00\x00\x10\x00\x10\x00"
            b"\xd8\x00\x00\x00\x35\x82\x88\xe2"
            b"\x05\x01\x28\x0a\x00\x00\x00\x0f"
            b"\x44\x00\x6f\x00\x6d\x00\x61\x00"
            b"\x69\x00\x6e\x00\x55\x00\x73\x00"
            b"\x65\x00\x72\x00\x43\x00\x4f\x00"
            b"\x4d\x00\x50\x00\x55\x00\x54\x00"
            b"\x45\x00\x52\x00\x86\xc3\x50\x97"
            b"\xac\x9c\xec\x10\x25\x54\x76\x4a"
            b"\x57\xcc\xcc\x19\xaa\xaa\xaa\xaa"
            b"\xaa\xaa\xaa\xaa\x68\xcd\x0a\xb8"
            b"\x51\xe5\x1c\x96\xaa\xbc\x92\x7b"
            b"\xeb\xef\x6a\x1c\x01\x01\x00\x00"
            b"\x00\x00\x00\x00\x00\x00\x00\x00"
            b"\x00\x00\x00\x00\xaa\xaa\xaa\xaa"
            b"\xaa\xaa\xaa\xaa\x00\x00\x00\x00"
            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"\x00\x00\x00\x00\x00\x00\x00\x00"
            b"\xc5\xda\xd2\x54\x4f\xc9\x79\x90"
            b"\x94\xce\x1c\xe9\x0b\xc9\xd0\x3e"
        )

        actual_message = \
            test_ntlm_context.create_authenticate_message("User", "Password",
                                                          "Domain", "COMPUTER")
        actual_session_security = test_ntlm_context.session_security

        assert actual_message == expected_message
        assert actual_session_security is None
    def connect(self, host_port):
        (host, port) = host_port
        ntlm_context = Ntlm(ntlm_compatibility=5)
        negotiate_message = ntlm_context.create_negotiate_message(
            self._domain, self._workstation).decode()
        resp = None
        try:
            self._sock.connect((self._proxy_ip, self._proxy_port))
            self._sock.send(
                NtlmProxyContext.negotiate_request.format(
                    host, str(port), negotiate_message))
            resp = self._sock.recv(4096)
        except socket.error:
            print(
                "Caught socket error trying to establish connection to proxy. Code {0}. Msg {1}"
                .format(code, msg))
            raise

        try:
            chal_msg = NtlmProxyContext.get_challenge(resp)
            ntlm_context.parse_challenge_message(chal_msg)
        except TypeError:
            print("Couldn't parse proxy challenge. Code {0}. Msg {1}".format(
                code, msg))
            if resp is not None:
                print("Challenge contents: {0}".format(resp))
            else:
                print("Challenge contents is 'None'")
            self._sock.close()

        authenticate_message = ntlm_context.create_authenticate_message(
            user_name=self._username,
            domain_name=self._domain,
            password=self._password,
            nthash=self._nthash,
            lmhash=self._lmhash).decode()
        resp = None
        try:
            self._sock.send(
                NtlmProxyContext.authenticate_request.format(
                    host, str(port), authenticate_message))
            resp = self._sock.recv(4096)
        except socket.error:
            print(
                "Caught socket error trying to send challenge response connection to proxy. Code {0}. Msg {1}"
                .format(code, msg))
            self._sock.close()
            raise

        if resp is None:
            print("Received an empty response to the challenge response")
            self._sock.close()

        if 'HTTP/1.1 200 Connection established' in resp:
            #logger.info('Ntlm proxy established connection')
            print(resp)
        elif 'HTTP/1.1 503 Service Unavailable' in resp:
            #print('Ntlm proxy response: Service Unavailable')
            print(resp)
            self._sock.close()
        elif 'HTTP/1.1 407 Proxy Authentication Required' in resp:
            #print('Ntlm proxy authentication failed')
            print(resp)
            self._sock.close()
            sys.exit(1)
        else:
            print('Ntlm proxy unknown error')
            print(resp)
            self._sock.close()
Пример #9
0
    def test_create_authenticate_message_without_security(self, monkeypatch):
        monkeypatch.setattr('os.urandom', lambda s: b"\xaa" * 8)
        monkeypatch.setattr('ntlm_auth.messages.get_version',
                            lambda s: b"\x05\x01\x28\x0A\x00\x00\x00\x0F")
        monkeypatch.setattr('ntlm_auth.messages.get_random_export_session_key',
                            lambda: b"\x55" * 16)
        monkeypatch.setattr('ntlm_auth.compute_response.get_windows_timestamp',
                            lambda: b"\x00" * 8)

        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\x03\x92\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.create_negotiate_message("Domain", "COMPUTER")
        test_ntlm_context.parse_challenge_message(test_challenge_string)

        expected_message = base64.b64encode(
            b"\x4e\x54\x4c\x4d\x53\x53\x50\x00"
            b"\x03\x00\x00\x00\x18\x00\x18\x00"
            b"\x6c\x00\x00\x00\x54\x00\x54\x00"
            b"\x84\x00\x00\x00\x0c\x00\x0c\x00"
            b"\x48\x00\x00\x00\x08\x00\x08\x00"
            b"\x54\x00\x00\x00\x10\x00\x10\x00"
            b"\x5c\x00\x00\x00\x10\x00\x10\x00"
            b"\xd8\x00\x00\x00\x01\x92\x8a\xe2"
            b"\x05\x01\x28\x0a\x00\x00\x00\x0f"
            b"\x44\x00\x6f\x00\x6d\x00\x61\x00"
            b"\x69\x00\x6e\x00\x55\x00\x73\x00"
            b"\x65\x00\x72\x00\x43\x00\x4f\x00"
            b"\x4d\x00\x50\x00\x55\x00\x54\x00"
            b"\x45\x00\x52\x00\x86\xc3\x50\x97"
            b"\xac\x9c\xec\x10\x25\x54\x76\x4a"
            b"\x57\xcc\xcc\x19\xaa\xaa\xaa\xaa"
            b"\xaa\xaa\xaa\xaa\x68\xcd\x0a\xb8"
            b"\x51\xe5\x1c\x96\xaa\xbc\x92\x7b"
            b"\xeb\xef\x6a\x1c\x01\x01\x00\x00"
            b"\x00\x00\x00\x00\x00\x00\x00\x00"
            b"\x00\x00\x00\x00\xaa\xaa\xaa\xaa"
            b"\xaa\xaa\xaa\xaa\x00\x00\x00\x00"
            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"\x00\x00\x00\x00\x00\x00\x00\x00"
            b"\xc5\xda\xd2\x54\x4f\xc9\x79\x90"
            b"\x94\xce\x1c\xe9\x0b\xc9\xd0\x3e")

        actual_message = \
            test_ntlm_context.create_authenticate_message("User", "Password",
                                                          "Domain", "COMPUTER")
        actual_session_security = test_ntlm_context.session_security

        assert actual_message == expected_message
        assert actual_session_security is None

        # now test the properties map up the the correct NtlmContext ones
        assert test_ntlm_context.authenticate_message == \
            test_ntlm_context._context._authenticate_message
        test_ntlm_context.authenticate_message = b"1"
        assert test_ntlm_context._context._authenticate_message == b"1"

        assert test_ntlm_context.challenge_message == \
            test_ntlm_context._context._challenge_message
        test_ntlm_context.challenge_message = b"2"
        assert test_ntlm_context._context._challenge_message == b"2"

        assert test_ntlm_context.negotiate_flags == \
            test_ntlm_context._context.negotiate_flags
        test_ntlm_context.negotiate_flags = 1
        assert test_ntlm_context._context.negotiate_flags == 1

        assert test_ntlm_context.negotiate_message == \
            test_ntlm_context._context._negotiate_message
        test_ntlm_context.negotiate_message = b"3"
        assert test_ntlm_context._context._negotiate_message == b"3"

        assert test_ntlm_context.ntlm_compatibility == \
            test_ntlm_context._context.ntlm_compatibility
        test_ntlm_context.ntlm_compatibility = 2
        assert test_ntlm_context._context.ntlm_compatibility == 2

        assert test_ntlm_context.session_security == \
            test_ntlm_context._context._session_security
        test_ntlm_context.session_security = b"4"
        assert test_ntlm_context._context._session_security == b"4"