def to_bytes(self): format = [self.scheme.encode('ascii'), b' '] auth = ntlm.create_NTLM_AUTHENTICATE_MESSAGE( self.type2.server_challenge, self.type1.user, self.base.domain, self.base.password, self.type2.flags) format.append(auth) return b''.join(format)
def ntlm_authenticate(smtp, username, password): # Send the NTLM Type 1 message -- Authentication Request msg = ntlm.create_NTLM_NEGOTIATE_MESSAGE(username) print(msg) code, response = smtp.docmd( "AUTH", "NTLM " + ntlm.create_NTLM_NEGOTIATE_MESSAGE(username).decode()) if code != SMTP_AUTH_CHALLENGE: raise SMTPException( "Server did not respond as expected to NTLM negotiate message") challenge, flags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(response) user_parts = username.split("\\", 1) DomainName = user_parts[0].upper() UserName = user_parts[1] msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(challenge, UserName, DomainName, password, flags) print(msg) code, response = smtp.docmd( "", ntlm.create_NTLM_AUTHENTICATE_MESSAGE(challenge, UserName, DomainName, password, flags).decode()) print(code) if code != SMTP_AUTH_OKAY: raise SMTPAuthenticationError(code, response)
def retry_using_http_NTLM_auth(self, auth_header_field, auth_header, response, auth_type, args): """Attempt to authenticate using HTTP NTLM challenge/response.""" if auth_header in response.request.headers: return response content_length = int( response.request.headers.get('Content-Length', '0'), base=10) if hasattr(response.request.body, 'seek'): if content_length > 0: response.request.body.seek(-content_length, 1) else: response.request.body.seek(0, 0) # Consume content and release the original connection # to allow our new request to reuse the same one. response.content response.raw.release_conn() request = response.request.copy() # initial auth header with username. will result in challenge msg = "%s\\%s" % (self.domain, self.username) if self.domain else self.username # ntlm returns the headers as a base64 encoded bytestring. Convert to # a string. auth = '%s %s' % (auth_type, ntlm.create_NTLM_NEGOTIATE_MESSAGE(msg).decode('ascii')) request.headers[auth_header] = auth # A streaming response breaks authentication. # This can be fixed by not streaming this request, which is safe # because the returned response3 will still have stream=True set if # specified in args. In addition, we expect this request to give us a # challenge and not the real content, so the content will be short # anyway. args_nostream = dict(args, stream=False) response2 = response.connection.send(request, **args_nostream) # needed to make NTLM auth compatible with requests-2.3.0 # Consume content and release the original connection # to allow our new request to reuse the same one. response2.content response2.raw.release_conn() request = response2.request.copy() # this is important for some web applications that store # authentication-related info in cookies (it took a long time to # figure out) if response2.headers.get('set-cookie'): request.headers['Cookie'] = response2.headers.get('set-cookie') # get the challenge auth_header_value = response2.headers[auth_header_field] auth_strip = auth_type + ' ' ntlm_header_value = next( s for s in (val.lstrip() for val in auth_header_value.split(',')) if s.startswith(auth_strip) ).strip() ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE( ntlm_header_value[len(auth_strip):] ) # build response # ntlm returns the headers as a base64 encoded bytestring. Convert to a # string. auth = '%s %s' % (auth_type, ntlm.create_NTLM_AUTHENTICATE_MESSAGE( ServerChallenge, self.username, self.domain, self.password, NegotiateFlags ).decode('ascii')) request.headers[auth_header] = auth response3 = response2.connection.send(request, **args) # Update the history. response3.history.append(response) response3.history.append(response2) return response3
from flask import Flask,request from ntlm3 import ntlm from tests.test_utils import username, password, domain app = Flask(__name__) REQUEST_2_TEMPLATE = '{0} %s' % ntlm.create_NTLM_NEGOTIATE_MESSAGE(domain + "\\" + username).decode('ascii') RESPONSE_2_NONCE = 'TlRMTVNTUAACAAAADAAMADAAAAAHAgMAESIzRFVmd4gAAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABYAZQB4AGEAbQBwAGwAZQAuAGMAbwBtAAMAJABTAEUAUgBWAEUAUgAuAGUAeABhAG0AcABsAGUALgBjAG8AbQAAAAAA' RESPONSE_2_TEMPLATE = '{0} %s' % RESPONSE_2_NONCE ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(RESPONSE_2_NONCE) REQUEST_3_TEMPLATE = '{0} %s' % ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge, username, domain, password, NegotiateFlags).decode('ascii') @app.route("/ntlm") def ntlm_auth(): return get_auth_response('NTLM') @app.route("/negotiate") def negotiate_auth(): return get_auth_response('Negotiate') @app.route("/both") def negotiate_and_ntlm_auth(): return get_auth_response('NTLM', advertise_nego_and_ntlm=True) def get_auth_response(auth_type, advertise_nego_and_ntlm=False): response_headers = {'WWW-Authenticate':auth_type if not advertise_nego_and_ntlm else 'Negotiate, NTLM'} status_code = 401 response = "auth with '%s\\%s':'%s'" % (domain, username, password)
from flask import Flask, request from ntlm3 import ntlm app = Flask(__name__) REQUEST_2_TEMPLATE = "{0} %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE("domain\\username").decode("ascii") RESPONSE_2_NONCE = "TlRMTVNTUAACAAAADAAMADAAAAAHAgMAESIzRFVmd4gAAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABYAZQB4AGEAbQBwAGwAZQAuAGMAbwBtAAMAJABTAEUAUgBWAEUAUgAuAGUAeABhAG0AcABsAGUALgBjAG8AbQAAAAAA" RESPONSE_2_TEMPLATE = "{0} %s" % RESPONSE_2_NONCE ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(RESPONSE_2_NONCE) REQUEST_3_TEMPLATE = "{0} %s" % ntlm.create_NTLM_AUTHENTICATE_MESSAGE( ServerChallenge, "username", "domain", "password", NegotiateFlags ).decode("ascii") @app.route("/ntlm") def ntlm_auth(): return get_auth_response("NTLM") @app.route("/negotiate") def negotiate_auth(): return get_auth_response("Negotiate") @app.route("/both") def negotiate_and_ntlm_auth(): return get_auth_response("NTLM", advertise_nego_and_ntlm=True)
from flask import Flask, request from ntlm3 import ntlm app = Flask(__name__) REQUEST_2 = 'NTLM %s' % ntlm.create_NTLM_NEGOTIATE_MESSAGE( "domain\\username").decode('ascii') RESPONSE_2 = 'NTLM TlRMTVNTUAACAAAADAAMADAAAAAHAgMAESIzRFVmd4gAAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABYAZQB4AGEAbQBwAGwAZQAuAGMAbwBtAAMAJABTAEUAUgBWAEUAUgAuAGUAeABhAG0AcABsAGUALgBjAG8AbQAAAAAA' ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE( RESPONSE_2[5:]) REQUEST_3 = 'NTLM %s' % ntlm.create_NTLM_AUTHENTICATE_MESSAGE( ServerChallenge, 'username', 'domain', 'password', NegotiateFlags).decode('ascii') @app.route("/") def ntlm_auth(): response_headers = {'WWW-Authenticate': 'NTLM'} status_code = 401 response = "auth with 'domain\\username':'******'" # 2nd request if request.headers.get('Authorization', '') == REQUEST_2: response_headers = {'WWW-Authenticate': RESPONSE_2} status_code = 401 # 3rd request elif request.headers.get('Authorization', '') == REQUEST_3: response_headers = {}
from flask import Flask,request from ntlm3 import ntlm app = Flask(__name__) REQUEST_2 = 'NTLM {0!s}'.format(ntlm.create_NTLM_NEGOTIATE_MESSAGE("domain\\username").decode('ascii')) RESPONSE_2 = 'NTLM TlRMTVNTUAACAAAADAAMADAAAAAHAgMAESIzRFVmd4gAAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABYAZQB4AGEAbQBwAGwAZQAuAGMAbwBtAAMAJABTAEUAUgBWAEUAUgAuAGUAeABhAG0AcABsAGUALgBjAG8AbQAAAAAA' ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(RESPONSE_2[5:]) REQUEST_3 = 'NTLM {0!s}'.format(ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge, 'username', 'domain', 'password', NegotiateFlags).decode('ascii')) @app.route("/") def ntlm_auth(): response_headers = {'WWW-Authenticate':'NTLM'} status_code = 401 response = "auth with 'domain\\username':'******'" # 2nd request if request.headers.get('Authorization','') == REQUEST_2: response_headers = {'WWW-Authenticate':RESPONSE_2} status_code = 401 # 3rd request elif request.headers.get('Authorization','') == REQUEST_3: response_headers = {} status_code = 200 response = "authed" return response,status_code,response_headers if __name__ == "__main__":
def retry_using_http_NTLM_auth(self, auth_header_field, auth_header, response, args): """Attempt to authenticate using HTTP NTLM challenge/response.""" if auth_header in response.request.headers: return response request = copy_request(response.request) content_length = int(request.headers.get('Content-Length', '0'), base=10) if hasattr(request.body, 'seek'): if content_length > 0: request.body.seek(-content_length, 1) else: request.body.seek(0, 0) adapter = self.adapter if self.session: session = self.session() if session: adapter = session.get_adapter(response.request.url) # initial auth header with username. will result in challenge msg = "%s\\%s" % (self.domain, self.username) if self.domain else self.username # ntlm returns the headers as a base64 encoded bytestring. Convert to a string. auth = 'NTLM %s' % ntlm.create_NTLM_NEGOTIATE_MESSAGE(msg).decode( 'ascii') request.headers[auth_header] = auth # A streaming response breaks authentication. # This can be fixed by not streaming this request, which is safe # because the returned response3 will still have stream=True set if # specified in args. In addition, we expect this request to give us a # challenge and not the real content, so the content will be short # anyway. args_nostream = dict(args, stream=False) response2 = adapter.send(request, **args_nostream) # needed to make NTLM auth compatible with requests-2.3.0 response2.content # this is important for some web applications that store # authentication-related info in cookies (it took a long time to # figure out) if response2.headers.get('set-cookie'): request.headers['Cookie'] = response2.headers.get('set-cookie') # get the challenge auth_header_value = response2.headers[auth_header_field] ntlm_header_value = list( filter(lambda s: s.startswith('NTLM '), auth_header_value.split(',')))[0].strip() ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE( ntlm_header_value[5:]) # build response request = copy_request(request) # ntlm returns the headers as a base64 encoded bytestring. Convert to a string. auth = 'NTLM %s' % ntlm.create_NTLM_AUTHENTICATE_MESSAGE( ServerChallenge, self.username, self.domain, self.password, NegotiateFlags).decode('ascii') request.headers[auth_header] = auth response3 = adapter.send(request, **args) # Update the history. response3.history.append(response) response3.history.append(response2) return response3
def retry_using_http_NTLM_auth(self, auth_header_field, auth_header, response, args): """Attempt to authenticate using HTTP NTLM challenge/response.""" if auth_header in response.request.headers: return response request = copy_request(response.request) content_length = int(request.headers.get("Content-Length", "0"), base=10) if hasattr(request.body, "seek"): if content_length > 0: request.body.seek(-content_length, 1) else: request.body.seek(0, 0) adapter = self.adapter if self.session: session = self.session() if session: adapter = session.get_adapter(response.request.url) # initial auth header with username. will result in challenge msg = "%s\\%s" % (self.domain, self.username) if self.domain else self.username # ntlm returns the headers as a base64 encoded bytestring. Convert to a string. auth = "NTLM %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE(msg).decode("ascii") request.headers[auth_header] = auth # A streaming response breaks authentication. # This can be fixed by not streaming this request, which is safe # because the returned response3 will still have stream=True set if # specified in args. In addition, we expect this request to give us a # challenge and not the real content, so the content will be short # anyway. args_nostream = dict(args, stream=False) response2 = adapter.send(request, **args_nostream) # needed to make NTLM auth compatible with requests-2.3.0 response2.content # this is important for some web applications that store # authentication-related info in cookies (it took a long time to # figure out) if response2.headers.get("set-cookie"): request.headers["Cookie"] = response2.headers.get("set-cookie") # get the challenge auth_header_value = response2.headers[auth_header_field] ntlm_header_value = list(filter(lambda s: s.startswith("NTLM "), auth_header_value.split(",")))[0].strip() ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(ntlm_header_value[5:]) # build response request = copy_request(request) # ntlm returns the headers as a base64 encoded bytestring. Convert to a string. auth = "NTLM %s" % ntlm.create_NTLM_AUTHENTICATE_MESSAGE( ServerChallenge, self.username, self.domain, self.password, NegotiateFlags ).decode("ascii") request.headers[auth_header] = auth response3 = adapter.send(request, **args) # Update the history. response3.history.append(response) response3.history.append(response2) return response3
def retry_using_http_NTLM_auth(self, auth_header_field, auth_header, response, auth_type, args): """Attempt to authenticate using HTTP NTLM challenge/response.""" if auth_header in response.request.headers: return response content_length = int(response.request.headers.get( 'Content-Length', '0'), base=10) if hasattr(response.request.body, 'seek'): if content_length > 0: response.request.body.seek(-content_length, 1) else: response.request.body.seek(0, 0) # Consume content and release the original connection # to allow our new request to reuse the same one. response.content response.raw.release_conn() request = response.request.copy() # initial auth header with username. will result in challenge if self._use_default_credentials: pkg_info = win32security.QuerySecurityPackageInfo(_package) clientauth = sspi.ClientAuth(_package) sec_buffer = win32security.PySecBufferDescType() error, auth = clientauth.authorize(sec_buffer) request.headers[auth_header] = '{} {}'.format( _package, b64encode(auth[0].Buffer).decode('ascii')) else: msg = "%s\\%s" % (self.domain, self.username) if self.domain else self.username # ntlm returns the headers as a base64 encoded bytestring. Convert to # a string. auth = '%s %s' % (auth_type, ntlm.create_NTLM_NEGOTIATE_MESSAGE( msg).decode('ascii')) request.headers[auth_header] = auth # A streaming response breaks authentication. # This can be fixed by not streaming this request, which is safe # because the returned response3 will still have stream=True set if # specified in args. In addition, we expect this request to give us a # challenge and not the real content, so the content will be short # anyway. args_nostream = dict(args, stream=False) response2 = response.connection.send(request, **args_nostream) # needed to make NTLM auth compatible with requests-2.3.0 # Consume content and release the original connection # to allow our new request to reuse the same one. response2.content response2.raw.release_conn() request = response2.request.copy() # this is important for some web applications that store # authentication-related info in cookies (it took a long time to # figure out) if response2.headers.get('set-cookie'): request.headers['Cookie'] = response2.headers.get('set-cookie') # get the challenge auth_header_value = response2.headers[auth_header_field] auth_strip = auth_type + ' ' ntlm_header_value = next( s for s in (val.lstrip() for val in auth_header_value.split(',')) if s.startswith(auth_strip)).strip() challenge_value = ntlm_header_value[len(auth_strip):] # build response if self._use_default_credentials: # Add challenge to security buffer tokenbuf = win32security.PySecBufferType(pkg_info['MaxToken'], sspicon.SECBUFFER_TOKEN) tokenbuf.Buffer = b64decode(challenge_value) sec_buffer.append(tokenbuf) # Perform next authorization step error, auth = clientauth.authorize(sec_buffer) request.headers[auth_header] = '{} {}'.format( _package, b64encode(auth[0].Buffer).decode('ascii')) else: ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE( challenge_value) # ntlm returns the headers as a base64 encoded bytestring. Convert to a # string. auth = '%s %s' % (auth_type, ntlm.create_NTLM_AUTHENTICATE_MESSAGE( ServerChallenge, self.username, self.domain, self.password, NegotiateFlags).decode('ascii')) request.headers[auth_header] = auth response3 = response2.connection.send(request, **args) # Update the history. response3.history.append(response) response3.history.append(response2) return response3