def connect_to_exchange_as_current_user(self, smtp): # Send the SMTP EHLO command code, response = smtp.ehlo() if code != self._config.SMTP_EHLO_OKAY: raise SMTPException( "Server did not respond as expected to EHLO command") sspiclient = sspi.ClientAuth('NTLM') # Generate the NTLM Type 1 message sec_buffer = None err, sec_buffer = sspiclient.authorize(sec_buffer) ntlm_message = self.asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 1 message -- Authentication Request code, response = smtp.docmd("AUTH", "NTLM " + ntlm_message) # Verify the NTLM Type 2 response -- Challenge Message if code != self._config.SMTP_AUTH_CHALLENGE: raise SMTPException( "Server did not respond as expected to NTLM negotiate message") # Generate the NTLM Type 3 message err, sec_buffer = sspiclient.authorize(base64.decodestring(response)) ntlm_message = self.asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 3 message -- Response Message #code, response = smtp.docmd("", ntlm_message) code, response = smtp.docmd(ntlm_message) if code != self._config.SMTP_AUTH_OKAY: raise SMTPAuthenticationError(code, response)
def _connect_to_exchange(self, smtp): code, response = smtp.ehlo() if code != SMTP_EHLO_OKAY: logging.error("Server did not respond as expected to EHLO command") raise smtplib.SMTPException( "Server did not respond as expected to EHLO command") sspiclient = sspi.ClientAuth('NTLM') # Generate the NTLM Type 1 message sec_buffer = None err, sec_buffer = sspiclient.authorize(sec_buffer) ntlm_message = asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 1 message -- Authentication Request code, response = smtp.docmd("AUTH", "NTLM " + ntlm_message) # Verify the NTLM Type 2 response -- Challenge Message if code != SMTP_AUTH_CHALLENGE: logging.error( "Server did not respond as expected to NTLM negotiate message") raise smtplib.SMTPException( "Server did not respond as expected to NTLM negotiate message") # Generate the NTLM Type 3 message err, sec_buffer = sspiclient.authorize(base64.decodebytes(response)) ntlm_message = asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 3 message -- Response Message code, response = smtp.docmd("", ntlm_message) if code != SMTP_AUTH_OKAY: logging.error("SMTPAuthenticationError") raise smtplib.SMTPAuthenticationError(code, response) # if this part is reached, the authentication was succesfull and emails can be sent. pass
def __init__(self): if "winkerberos" in sys.modules: status, self.ctx = winkerberos.authGSSClientInit("NTLM", gssflags=0, mech_oid=winkerberos.GSS_MECH_OID_SPNEGO) self.get_response = self.get_response_wkb else: self.sspi_client = sspi.ClientAuth("NTLM", os.environ.get("USERNAME"), scflags=0) self.get_response = self.get_response_sspi
def connect_to_exchange_as_current_user(smtp): """Example: >>> import smtplib >>> smtp = smtplib.SMTP("mail.huajingsec.com") >>> connect_to_exchange_as_current_user(smtp) """ # Send the SMTP EHLO command code, response = smtp.ehlo() if code != SMTP_EHLO_OKAY: raise SMTPException( "Server did not respond as expected to EHLO command") sspiclient = sspi.ClientAuth('NTLM') # Generate the NTLM Type 1 message sec_buffer = None err, sec_buffer = sspiclient.authorize(sec_buffer) print(sec_buffer) ntlm_message = asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 1 message -- Authentication Request code, response = smtp.docmd("AUTH", "NTLM " + ntlm_message) # Verify the NTLM Type 2 response -- Challenge Message if code != SMTP_AUTH_CHALLENGE: raise SMTPException( "Server did not respond as expected to NTLM negotiate message") # Generate the NTLM Type 3 message err, sec_buffer = sspiclient.authorize( base64.b64decode(response.encode(encoding='utf-8'))) ntlm_message = asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 3 message -- Response Message code, response = smtp.docmd(ntlm_message) # code, response = smtp.docmd("", ntlm_message) if code != SMTP_AUTH_OKAY: raise SMTPAuthenticationError(code, response)
def __init__(self, proxy_type): if proxy_type == "NTLM": self.ctx = sspi.ClientAuth("NTLM", os.environ.get("USERNAME"), scflags=0) self.get_response = self.get_response_sspi else: _, self.ctx = winkerberos.authGSSClientInit("HTTP@" + State.proxy_server[0][0], gssflags=0, mech_oid=winkerberos.GSS_MECH_OID_SPNEGO) self.get_response = self.get_response_wkb
def _create_sspi_authenticator(self, auth_info, targetspn, scflags): # Use the Negotiate package which means we'll use Kerberos if it's # supported/available and fall back to NTLM otherwise. ca = sspi.ClientAuth("Negotiate", auth_info=auth_info, targetspn=targetspn, scflags=scflags) return ca
def _create_sspi_authenticator(self, auth_info, targetspn, scflags): # explicitly specifying 'Kerberos' or 'NTLM' will also work # here, but technically if we say the SASL type is GSS-SPNEGO, # we're supposed to use 'Negotiate' ca = sspi.ClientAuth('Negotiate', auth_info=auth_info, targetspn=targetspn, scflags=scflags) return ca
def do_ntlm_auth(self, resp_auth_hdr, req_auth_hdr, resp, kwargs): if hasattr(resp.request.body, "seek"): content_length = int( resp.request.headers.get("Content-Length", "0")) if content_length > 0: resp.request.body.seek(-content_length, 1) else: resp.request.body.seek(0, 0) # Consume content and release the original connection # to allow our new request to reuse the same one. resp.content resp.raw.release_conn() new_req = resp.request.copy() # Prepare authorization header for the new request. ca = sspi.ClientAuth("NTLM", auth_info=(self.username, self.domain, self.password)) _, data = ca.authorize(None) new_req.headers[req_auth_hdr] = "NTLM %s" % base64.b64encode( data[0].Buffer) # A streaming response breaks authentication. # # This can be fixed by not streaming this request, which is safe # because the returned resp3 will still have stream=True set if # specified in kwargs. In addition, we expect this request to give us a # challenge and not the real content, so the content will be short # anyway. kwargs_nostream = dict(kwargs, stream=False) resp2 = resp.connection.send(new_req, **kwargs_nostream) # Consume content and release the original connection # to allow our new request to reuse the same one. resp2.content resp2.raw.release_conn() new_req = resp2.request.copy() challenge = resp2.headers[resp_auth_hdr] challenge = filter(lambda s: s.startswith("NTLM "), challenge.split(","))[0].strip().split()[1] challenge = base64.b64decode(challenge) # Build response of challenge _, data = ca.authorize(challenge) new_req.headers[req_auth_hdr] = "NTLM %s" % base64.b64encode( data[0].Buffer) resp3 = resp2.connection.send(new_req, **kwargs) # Update the history resp3.history.append(resp) resp3.history.append(resp2) return resp3
def _doAuth(self, pkg_name): sspiclient = sspi.ClientAuth(pkg_name, targetspn=win32api.GetUserName()) sspiserver = sspi.ServerAuth(pkg_name) sec_buffer = None err = 1 while err != 0: err, sec_buffer = sspiclient.authorize(sec_buffer) err, sec_buffer = sspiserver.authorize(sec_buffer) return sspiclient, sspiserver
def ssh_init_sec_context(self, target, desired_mech=None, username=None, recv_token=None): """ Initialize a SSPI context. :param str username: The name of the user who attempts to login :param str target: The FQDN of the target to connect to :param str desired_mech: The negotiated SSPI mechanism ("pseudo negotiated" mechanism, because we support just the krb5 mechanism :-)) :param recv_token: The SSPI token received from the Server :raises: `.SSHException` -- Is raised if the desired mechanism of the client is not supported :return: A ``String`` if the SSPI has returned a token or ``None`` if no token was returned """ from pyasn1.codec.der import decoder self._username = username self._gss_host = target error = 0 targ_name = "host/" + self._gss_host if desired_mech is not None: mech, __ = decoder.decode(desired_mech) if mech.__str__() != self._krb5_mech: raise SSHException("Unsupported mechanism OID.") try: if recv_token is None: self._gss_ctxt = sspi.ClientAuth("Kerberos", scflags=self._gss_flags, targetspn=targ_name) error, token = self._gss_ctxt.authorize(recv_token) token = token[0].Buffer except pywintypes.error as e: e.strerror += ", Target: {}".format(e, self._gss_host) raise if error == 0: """ if the status is GSS_COMPLETE (error = 0) the context is fully established an we can set _gss_ctxt_status to True. """ self._gss_ctxt_status = True token = None """ You won't get another token if the context is fully established, so i set token to None instead of "" """ return token
def init_context(self): flags = sspicon.ISC_REQ_INTEGRITY | \ sspicon.ISC_REQ_CONFIDENTIALITY | \ sspicon.ISC_REQ_REPLAY_DETECT | \ sspicon.ISC_REQ_SEQUENCE_DETECT | \ sspicon.ISC_REQ_MUTUAL_AUTH self._context = sspi.ClientAuth(pkg_name=self.auth_provider, auth_info=(self.username, self.domain, self.password), targetspn=self._target_spn, scflags=flags)
def fixup(self): try: fullName = self.context.getFullname() xml = self.getXml() firstFullName = str( xml.xpath(self.firstSend)[0].get("fullName")) firstFullName = firstFullName[firstFullName.index('.') + 1:] if fullName.find( firstFullName ) > -1 and SspiAuthenticationFixup._firstObj != self.context: #scflags = sspicon.ISC_REQ_INTEGRITY|sspicon.ISC_REQ_SEQUENCE_DETECT|\ # sspicon.ISC_REQ_REPLAY_DETECT|sspicon.ISC_REQ_CONFIDENTIALITY scflags = sspicon.ISC_REQ_INTEGRITY | sspicon.ISC_REQ_SEQUENCE_DETECT | \ sspicon.ISC_REQ_REPLAY_DETECT SspiAuthenticationFixup._firstObj = self.context SspiAuthenticationFixup._sspi = sspi.ClientAuth( "Negotiate", "", # client_name (self.username, self.workgroup, self.password), # auth_info None, # targetsn (target security context provider) scflags, #scflags # None, # security context flags ) (done, data) = SspiAuthenticationFixup._sspi.authorize(None) data = data[0].Buffer SspiAuthenticationFixup._data = data return data if fullName.find(firstFullName) > -1: return SspiAuthenticationFixup._data secondFullName = str( xml.xpath(self.secondSend)[0].get("fullName")) secondFullName = secondFullName[secondFullName.index('.') + 1:] if fullName.find( secondFullName ) > -1 and SspiAuthenticationFixup._secondObj != self.context: inputData = self.context.getInternalValue() if len(inputData) < 5: return None (done, data) = SspiAuthenticationFixup._sspi.authorize(inputData) data = data[0].Buffer SspiAuthenticationFixup._secondObj = self.context SspiAuthenticationFixup._data = data return data if fullName.find(secondFullName) > -1: return SspiAuthenticationFixup._data except: print("!!! EXCEPTION !!!") print(repr(sys.exc_info())) pass
def connectMSExchange(server): """ Creates a connection for the inputted server to a Microsoft Exchange server. :param server | <smtplib.SMTP> :usage |>>> import smtplib |>>> import projex.notify |>>> smtp = smtplib.SMTP('mail.server.com') |>>> projex.notify.connectMSExchange(smtp) :return (<bool> success, <str> reason) """ if not sspi: return False, 'No sspi module found.' # send the SMTP EHLO command code, response = server.ehlo() if code != SMTP_EHLO_OKAY: return False, 'Server did not respond to EHLO command.' sspi_client = sspi.ClientAuth('NTLM') # generate NTLM Type 1 message sec_buffer = None err, sec_buffer = sspi_client.authorize(sec_buffer) # noinspection PyShadowingBuiltins buffer = sec_buffer[0].Buffer ntlm_message = base64.encodestring(buffer).replace('\n', '') # send NTLM Type 1 message -- Authentication Request code, response = server.docmd('AUTH', 'NTLM ' + ntlm_message) # verify the NTLM Type 2 response -- Challenge Message if code != SMTP_AUTH_CHALLENGE: msg = 'Server did not respond as expected to NTLM negotiate message' return False, msg # generate NTLM Type 3 message err, sec_buffer = sspi_client.authorize(base64.decodestring(response)) # noinspection PyShadowingBuiltins buffer = sec_buffer[0].Buffer ntlm_message = base64.encodestring(buffer).replace('\n', '') # send the NTLM Type 3 message -- Response Message code, response = server.docmd('', ntlm_message) if code != SMTP_AUTH_OKAY: return False, response return True, ''
def __init__(self, pkgName): PI.IClientAuthenticationPlugin.__init__(self) flags = sspicon.ISC_REQ_INTEGRITY | \ sspicon.ISC_REQ_SEQUENCE_DETECT | \ sspicon.ISC_REQ_REPLAY_DETECT | \ sspicon.ISC_REQ_CONFIDENTIALITY | \ sspicon.ISC_REQ_DELEGATE #ISC_REQ_USE_DCE_STYLE | ISC_REQ_DELEGATE | #ISC_REQ_MUTUAL_AUTH |ISC_REQ_REPLAY_DETECT | #ISC_REQ_SEQUENCE_DETECT |ISC_REQ_CONFIDENTIALITY | #ISC_REQ_CONNECTION self.mClient = sspi.ClientAuth(pkgName, scflags=flags) self.mAvatar = None self.mAuthenticationDeferred = twisted.internet.defer.Deferred()
def __connect_to_exchange(self, smtp): ''' Connects to an exchange server for SMTP authentication. This uses NTLM method which attempts to authenticate as the currently logged in user. This means whatever account is used to run this process must have access to the exchange server for sending email. Example: >>> import smtplib >>> smtp = smtplib.SMTP("my.smtp.server") >>> __connect_to_exchange(smtp) ''' # NTLM Guide -- http://curl.haxx.se/rfc/ntlm.html # Send the SMTP EHLO command code, response = smtp.ehlo() if code != SMTP_EHLO_OKAY: raise SMTPException( "Server did not respond as expected to EHLO command") sspiclient = sspi.ClientAuth('NTLM') # login as current user # Generate the NTLM Type 1 message sec_buffer = None err, sec_buffer = sspiclient.authorize(sec_buffer) ntlm_message = self.__asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 1 message -- Authentication Request code, response = smtp.docmd("AUTH", "NTLM " + ntlm_message) # Verify the NTLM Type 2 response -- Challenge Message if code != SMTP_AUTH_CHALLENGE: raise SMTPException( "Server did not respond as expected to NTLM negotiate message") # Generate the NTLM Type 3 message err, sec_buffer = sspiclient.authorize(base64.decodestring(response)) ntlm_message = self.__asbase64(sec_buffer[0].Buffer) if err: self.__root_logger.warning(('Error while authenticating to ' 'exchange server')) # Send the NTLM Type 3 message -- Response Message code, response = smtp.docmd("", ntlm_message) if code != SMTP_AUTH_OKAY: raise SMTPAuthenticationError(code, response)
def get_krb_http_auth(host): hostname = host.split(':')[0] # remove port if os.name == 'nt': s = sspi.ClientAuth('Kerberos', targetspn="HTTP/" + hostname) a,b = s.authorize(None) auth = encodestring(b[0].Buffer).replace("\012", "") else: # On Linux need kerberos.so. Getting kerberos.so: # git clone https://github.com/apple/ccs-pykerberos.git # cd ccs-pykerberos.git # python setup.py build # --> kerberos.so in build/libxxx/ --> copy to same dir as python code __, krb_context = kerberos.authGSSClientInit("HTTP@" + hostname) kerberos.authGSSClientStep(krb_context, "") auth = kerberos.authGSSClientResponse(krb_context) return auth
def __init__(self, username, password, server): log.info("Setting up SSPI Security Context for Windows auth") self._call_counter = 0 flags = sspicon.ISC_REQ_INTEGRITY | \ sspicon.ISC_REQ_CONFIDENTIALITY | \ sspicon.ISC_REQ_REPLAY_DETECT | \ sspicon.ISC_REQ_SEQUENCE_DETECT | \ sspicon.ISC_REQ_MUTUAL_AUTH domain, username = _split_username_and_domain(username) # We could use the MECH to derive the package name but we are just # better off using Negotiate and lettings Windows do all the heavy # lifting. self._context = sspi.ClientAuth(pkg_name='Negotiate', auth_info=(username, domain, password), targetspn="cifs/%s" % server, scflags=flags)
def sspi_client(): c = http.client.HTTPConnection("localhost", options.port) c.connect() # Do the auth dance. ca = sspi.ClientAuth(options.package, targetspn=options.target_spn) data = None while 1: err, out_buf = ca.authorize(data) _send_msg(c.sock, out_buf[0].Buffer) if err == 0: break data = _get_msg(c.sock) print("Auth dance complete - sending a few encryted messages") # Assume out data is sensitive - encrypt the message. for data in "Hello from the client".split(): blob, key = ca.encrypt(data) _send_msg(c.sock, blob) _send_msg(c.sock, key) c.sock.close() print("Client completed.")
def _PassthroughLoginSSPI(self, host, sessionMgr, passthroughAuthPackage): """ Passthrough Authentication """ userSession = None try: from base64 import b64encode, b64decode import sspi except ImportError as err: LogException(err) return userSession try: # Create client authorization clientAuth = sspi.ClientAuth(passthroughAuthPackage) secBufDesc = None outSecBufDesc = None err = True while err: # Call authorization API err, outSecBufDesc = clientAuth.authorize(secBufDesc) # LoginBySSPI requires token to be base64 encoded secToken = b64encode(outSecBufDesc[0].Buffer) try: userSession = sessionMgr.LoginBySSPI(secToken) # No exception => logged in del secToken break except vim.fault.SSPIChallenge as err: # Continue sspi challenges # Decode token back to native format outSecBufDesc[0].Buffer = b64decode(err.base64Token) secBufDesc = outSecBufDesc # Cleanup del clientAuth del outSecBufDesc except sspi.error as err: logging.error(err.message) return userSession
def __init__(self, user=None): if not user: user = win32api.GetUserName() self.sspi_client = sspi.ClientAuth("NTLM", user, scflags=0)
def _gssapi_sspi_test(self): """ Test the used methods of python-gssapi or sspi, sspicon from pywin32. """ try: import gssapi if ( hasattr(gssapi, "__title__") and gssapi.__title__ == "python-gssapi" ): _API = "PYTHON-GSSAPI-OLD" else: _API = "PYTHON-GSSAPI-NEW" except ImportError: import sspicon import sspi _API = "SSPI" c_token = None gss_ctxt_status = False mic_msg = b"G'day Mate!" if _API == "PYTHON-GSSAPI-OLD": if self.server_mode: gss_flags = ( gssapi.C_PROT_READY_FLAG, gssapi.C_INTEG_FLAG, gssapi.C_MUTUAL_FLAG, gssapi.C_DELEG_FLAG, ) else: gss_flags = ( gssapi.C_PROT_READY_FLAG, gssapi.C_INTEG_FLAG, gssapi.C_DELEG_FLAG, ) # Initialize a GSS-API context. ctx = gssapi.Context() ctx.flags = gss_flags krb5_oid = gssapi.OID.mech_from_string(self.krb5_mech) target_name = gssapi.Name( "host@" + self.targ_name, gssapi.C_NT_HOSTBASED_SERVICE ) gss_ctxt = gssapi.InitContext( peer_name=target_name, mech_type=krb5_oid, req_flags=ctx.flags ) if self.server_mode: c_token = gss_ctxt.step(c_token) gss_ctxt_status = gss_ctxt.established self.assertEquals(False, gss_ctxt_status) # Accept a GSS-API context. gss_srv_ctxt = gssapi.AcceptContext() s_token = gss_srv_ctxt.step(c_token) gss_ctxt_status = gss_srv_ctxt.established self.assertNotEquals(None, s_token) self.assertEquals(True, gss_ctxt_status) # Establish the client context c_token = gss_ctxt.step(s_token) self.assertEquals(None, c_token) else: while not gss_ctxt.established: c_token = gss_ctxt.step(c_token) self.assertNotEquals(None, c_token) # Build MIC mic_token = gss_ctxt.get_mic(mic_msg) if self.server_mode: # Check MIC status = gss_srv_ctxt.verify_mic(mic_msg, mic_token) self.assertEquals(0, status) elif _API == "PYTHON-GSSAPI-NEW": if self.server_mode: gss_flags = ( gssapi.RequirementFlag.protection_ready, gssapi.RequirementFlag.integrity, gssapi.RequirementFlag.mutual_authentication, gssapi.RequirementFlag.delegate_to_peer, ) else: gss_flags = ( gssapi.RequirementFlag.protection_ready, gssapi.RequirementFlag.integrity, gssapi.RequirementFlag.delegate_to_peer, ) # Initialize a GSS-API context. krb5_oid = gssapi.MechType.kerberos target_name = gssapi.Name( "host@" + self.targ_name, name_type=gssapi.NameType.hostbased_service, ) gss_ctxt = gssapi.SecurityContext( name=target_name, flags=gss_flags, mech=krb5_oid, usage="initiate", ) if self.server_mode: c_token = gss_ctxt.step(c_token) gss_ctxt_status = gss_ctxt.complete self.assertEquals(False, gss_ctxt_status) # Accept a GSS-API context. gss_srv_ctxt = gssapi.SecurityContext(usage="accept") s_token = gss_srv_ctxt.step(c_token) gss_ctxt_status = gss_srv_ctxt.complete self.assertNotEquals(None, s_token) self.assertEquals(True, gss_ctxt_status) # Establish the client context c_token = gss_ctxt.step(s_token) self.assertEquals(None, c_token) else: while not gss_ctxt.complete: c_token = gss_ctxt.step(c_token) self.assertNotEquals(None, c_token) # Build MIC mic_token = gss_ctxt.get_signature(mic_msg) if self.server_mode: # Check MIC status = gss_srv_ctxt.verify_signature(mic_msg, mic_token) self.assertEquals(0, status) else: gss_flags = ( sspicon.ISC_REQ_INTEGRITY | sspicon.ISC_REQ_MUTUAL_AUTH | sspicon.ISC_REQ_DELEGATE ) # Initialize a GSS-API context. target_name = "host/" + socket.getfqdn(self.targ_name) gss_ctxt = sspi.ClientAuth( "Kerberos", scflags=gss_flags, targetspn=target_name ) if self.server_mode: error, token = gss_ctxt.authorize(c_token) c_token = token[0].Buffer self.assertEquals(0, error) # Accept a GSS-API context. gss_srv_ctxt = sspi.ServerAuth("Kerberos", spn=target_name) error, token = gss_srv_ctxt.authorize(c_token) s_token = token[0].Buffer # Establish the context. error, token = gss_ctxt.authorize(s_token) c_token = token[0].Buffer self.assertEquals(None, c_token) self.assertEquals(0, error) # Build MIC mic_token = gss_ctxt.sign(mic_msg) # Check MIC gss_srv_ctxt.verify(mic_msg, mic_token) else: error, token = gss_ctxt.authorize(c_token) c_token = token[0].Buffer self.assertNotEquals(0, error)
def test_2_gssapi_sspi(self): """ Test the used methods of python-gssapi or sspi, sspicon from pywin32. """ _API = "MIT" try: import gssapi except ImportError: import sspicon import sspi _API = "SSPI" c_token = None gss_ctxt_status = False mic_msg = b"G'day Mate!" if _API == "MIT": if server_mode: gss_flags = (gssapi.C_PROT_READY_FLAG, gssapi.C_INTEG_FLAG, gssapi.C_MUTUAL_FLAG, gssapi.C_DELEG_FLAG) else: gss_flags = (gssapi.C_PROT_READY_FLAG, gssapi.C_INTEG_FLAG, gssapi.C_DELEG_FLAG) # Initialize a GSS-API context. ctx = gssapi.Context() ctx.flags = gss_flags krb5_oid = gssapi.OID.mech_from_string(krb5_mech) target_name = gssapi.Name("host@" + targ_name, gssapi.C_NT_HOSTBASED_SERVICE) gss_ctxt = gssapi.InitContext(peer_name=target_name, mech_type=krb5_oid, req_flags=ctx.flags) if server_mode: c_token = gss_ctxt.step(c_token) gss_ctxt_status = gss_ctxt.established self.assertEquals(False, gss_ctxt_status) # Accept a GSS-API context. gss_srv_ctxt = gssapi.AcceptContext() s_token = gss_srv_ctxt.step(c_token) gss_ctxt_status = gss_srv_ctxt.established self.assertNotEquals(None, s_token) self.assertEquals(True, gss_ctxt_status) # Establish the client context c_token = gss_ctxt.step(s_token) self.assertEquals(None, c_token) else: while not gss_ctxt.established: c_token = gss_ctxt.step(c_token) self.assertNotEquals(None, c_token) # Build MIC mic_token = gss_ctxt.get_mic(mic_msg) if server_mode: # Check MIC status = gss_srv_ctxt.verify_mic(mic_msg, mic_token) self.assertEquals(0, status) else: gss_flags = (sspicon.ISC_REQ_INTEGRITY | sspicon.ISC_REQ_MUTUAL_AUTH | sspicon.ISC_REQ_DELEGATE) # Initialize a GSS-API context. target_name = "host/" + socket.getfqdn(targ_name) gss_ctxt = sspi.ClientAuth("Kerberos", scflags=gss_flags, targetspn=target_name) if server_mode: error, token = gss_ctxt.authorize(c_token) c_token = token[0].Buffer self.assertEquals(0, error) # Accept a GSS-API context. gss_srv_ctxt = sspi.ServerAuth("Kerberos", spn=target_name) error, token = gss_srv_ctxt.authorize(c_token) s_token = token[0].Buffer # Establish the context. error, token = gss_ctxt.authorize(s_token) c_token = token[0].Buffer self.assertEquals(None, c_token) self.assertEquals(0, error) # Build MIC mic_token = gss_ctxt.sign(mic_msg) # Check MIC gss_srv_ctxt.verify(mic_msg, mic_token) else: error, token = gss_ctxt.authorize(c_token) c_token = token[0].Buffer self.assertNotEquals(0, error)
def _retry_using_http_Negotiate_auth(self, response, scheme, args): if 'Authorization' in response.request.headers: return response if self._host is None: targeturl = urlparse(response.request.url) self._host = targeturl.hostname try: self._host = socket.getaddrinfo(self._host, None, 0, 0, 0, socket.AI_CANONNAME)[0][3] except socket.gaierror as e: _logger.info( 'Skipping canonicalization of name %s due to error: %s', self._host, e) targetspn = '{}/{}'.format(self._service, self._host) # Set up SSPI connection structure pkg_info = win32security.QuerySecurityPackageInfo(scheme) clientauth = sspi.ClientAuth(scheme, targetspn=targetspn, auth_info=self._auth_info) sec_buffer = win32security.PySecBufferDescType() # Channel Binding Hash (aka Extended Protection for Authentication) # If this is a SSL connection, we need to hash the peer certificate, prepend the RFC5929 channel binding type, # and stuff it into a SEC_CHANNEL_BINDINGS structure. # This should be sent along in the initial handshake or Kerberos auth will fail. if hasattr(response, 'peercert') and response.peercert is not None: md = hashlib.sha256() md.update(response.peercert) appdata = 'tls-server-end-point:'.encode('ASCII') + md.digest() cbtbuf = win32security.PySecBufferType( pkg_info['MaxToken'], sspicon.SECBUFFER_CHANNEL_BINDINGS) cbtbuf.Buffer = struct.pack('LLLLLLLL{}s'.format(len(appdata)), 0, 0, 0, 0, 0, 0, len(appdata), 32, appdata) sec_buffer.append(cbtbuf) 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() # this is important for some web applications that store # authentication-related info in cookies if response.headers.get('set-cookie'): request.headers['Cookie'] = response.headers.get('set-cookie') # Send initial challenge auth header try: error, auth = clientauth.authorize(sec_buffer) request.headers['Authorization'] = '{} {}'.format( scheme, base64.b64encode(auth[0].Buffer).decode('ASCII')) _logger.debug( 'Sending Initial Context Token - error={} authenticated={}'. format(error, clientauth.authenticated)) except pywintypes.error as e: _logger.error('Error calling {}: {}'.format(e[1], e[2]), exc_info=e) return response # 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) # Should get another 401 if we are doing challenge-response (NTLM) if response2.status_code != 401: if response2.status_code == 200: # Kerberos may have succeeded; if so, finalize our auth context final = response2.headers.get('WWW-Authenticate') if final is not None: try: # Sometimes Windows seems to forget to prepend 'Negotiate' to the success response, # and we get just a bare chunk of base64 token. Not sure why. final = final.replace(scheme, '', 1).lstrip() tokenbuf = win32security.PySecBufferType( pkg_info['MaxToken'], sspicon.SECBUFFER_TOKEN) tokenbuf.Buffer = base64.b64decode(final) sec_buffer.append(tokenbuf) error, auth = clientauth.authorize(sec_buffer) _logger.debug( 'Kerberos Authentication succeeded - error={} authenticated={}' .format(error, clientauth.authenticated)) except TypeError: pass # Regardless of whether or not we finalized our auth context, # without a 401 we've got nothing to do. Update the history and return. response2.history.append(response) return response2 # 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() # Keep passing the cookies along if response2.headers.get('set-cookie'): request.headers['Cookie'] = response2.headers.get('set-cookie') # Extract challenge message from server challenge = [ val[len(scheme) + 1:] for val in response2.headers.get( 'WWW-Authenticate', '').split(', ') if scheme in val ] if len(challenge) != 1: raise HTTPError( 'Did not get exactly one {} challenge from server.'.format( scheme)) # Add challenge to security buffer tokenbuf = win32security.PySecBufferType(pkg_info['MaxToken'], sspicon.SECBUFFER_TOKEN) tokenbuf.Buffer = base64.b64decode(challenge[0]) sec_buffer.append(tokenbuf) _logger.debug('Got Challenge Token (NTLM)') # Perform next authorization step error, auth = clientauth.authorize(sec_buffer) request.headers['Authorization'] = '{} {}'.format( scheme, base64.b64encode(auth[0].Buffer).decode('ASCII')) _logger.debug('Sending Response - error={} authenticated={}'.format( error, clientauth.authenticated)) response3 = response2.connection.send(request, **args) # Update the history and return response3.history.append(response) response3.history.append(response2) return response3
def _gssapi_sspi_test(self): try: import gssapi _API = "MIT-NEW" except ImportError: import sspicon import sspi _API = "SSPI" c_token = None gss_ctxt_status = False mic_msg = b"G'day Mate!" if _API == "MIT-NEW": if self.server_mode: gss_flags = (gssapi.RequirementFlag.protection_ready, gssapi.RequirementFlag.integrity, gssapi.RequirementFlag.mutual_authentication, gssapi.RequirementFlag.delegate_to_peer) else: gss_flags = (gssapi.RequirementFlag.protection_ready, gssapi.RequirementFlag.integrity, gssapi.RequirementFlag.delegate_to_peer) # Initialize a GSS-API context. krb5_oid = gssapi.MechType.kerberos target_name = gssapi.Name( "host@" + self.targ_name, name_type=gssapi.NameType.hostbased_service) gss_ctxt = gssapi.SecurityContext(name=target_name, flags=gss_flags, mech=krb5_oid, usage='initiate') if self.server_mode: c_token = gss_ctxt.step(c_token) gss_ctxt_status = gss_ctxt.complete self.assertEqual(False, gss_ctxt_status) # Accept a GSS-API context. gss_srv_ctxt = gssapi.SecurityContext(usage='accept') s_token = gss_srv_ctxt.step(c_token) gss_ctxt_status = gss_srv_ctxt.complete self.assertNotEqual(None, s_token) self.assertEqual(True, gss_ctxt_status) # Establish the client context c_token = gss_ctxt.step(s_token) self.assertEqual(None, c_token) else: while not gss_ctxt.complete: c_token = gss_ctxt.step(c_token) self.assertNotEqual(None, c_token) # Build MIC mic_token = gss_ctxt.get_signature(mic_msg) if self.server_mode: # Check MIC status = gss_srv_ctxt.verify_signature(mic_msg, mic_token) self.assertEqual(0, status) else: gss_flags = (sspicon.ISC_REQ_INTEGRITY | sspicon.ISC_REQ_MUTUAL_AUTH | sspicon.ISC_REQ_DELEGATE) # Initialize a GSS-API context. target_name = "host/" + socket.getfqdn(self.targ_name) gss_ctxt = sspi.ClientAuth("Kerberos", scflags=gss_flags, targetspn=target_name) if self.server_mode: error, token = gss_ctxt.authorize(c_token) c_token = token[0].Buffer self.assertEqual(0, error) # Accept a GSS-API context. gss_srv_ctxt = sspi.ServerAuth("Kerberos", spn=target_name) error, token = gss_srv_ctxt.authorize(c_token) s_token = token[0].Buffer # Establish the context. error, token = gss_ctxt.authorize(s_token) c_token = token[0].Buffer self.assertEqual(None, c_token) self.assertEqual(0, error) # Build MIC mic_token = gss_ctxt.sign(mic_msg) # Check MIC gss_srv_ctxt.verify(mic_msg, mic_token) else: error, token = gss_ctxt.authorize(c_token) c_token = token[0].Buffer self.assertNotEqual(0, error)
""" pkg_name='Kerberos' sspiclient=SSPIClient(pkg_name, win32api.GetUserName(), ## target spn is ourself None, None, ## use none for client name and authentication information for current context ## u'username', (u'username',u'domain.com',u'passwd'), sspicon.ISC_REQ_INTEGRITY|sspicon.ISC_REQ_SEQUENCE_DETECT|sspicon.ISC_REQ_REPLAY_DETECT| sspicon.ISC_REQ_DELEGATE|sspicon.ISC_REQ_CONFIDENTIALITY|sspicon.ISC_REQ_USE_SESSION_KEY) sspiserver=SSPIServer(pkg_name, None, sspicon.ASC_REQ_INTEGRITY|sspicon.ASC_REQ_SEQUENCE_DETECT|sspicon.ASC_REQ_REPLAY_DETECT| sspicon.ASC_REQ_DELEGATE|sspicon.ASC_REQ_CONFIDENTIALITY|sspicon.ASC_REQ_STREAM|sspicon.ASC_REQ_USE_SESSION_KEY) """ pkg_name = 'NTLM' # Setup the 2 contexts. sspiclient = sspi.ClientAuth(pkg_name) sspiserver = sspi.ServerAuth(pkg_name) # Perform the authentication dance, each loop exchanging more information # on the way to completing authentication. sec_buffer = None while 1: err, sec_buffer = sspiclient.authorize(sec_buffer) err, sec_buffer = sspiserver.authorize(sec_buffer) if err == 0: break # The server can now impersonate the client. In this demo the 2 users will # always be the same. sspiserver.ctxt.ImpersonateSecurityContext() print('Impersonated user: ',
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