async def authenticate(self, authData = None, flags = ISC_REQ.CONNECTION, seq_number = 0, is_rpc = False): try: if is_rpc == True: if self.iterations == 0: flags = ISC_REQ.CONFIDENTIALITY | \ ISC_REQ.INTEGRITY | \ ISC_REQ.MUTUAL_AUTH | \ ISC_REQ.REPLAY_DETECT | \ ISC_REQ.SEQUENCE_DETECT|\ ISC_REQ.USE_DCE_STYLE status, ctxattr, apreq, err = await self.ksspi.authenticate('KERBEROS', '', 'cifs/%s' % self.settings.target, 3, flags.value, authdata = b'') if err is not None: raise err self.iterations += 1 return apreq, True, None elif self.iterations == 1: status, ctxattr, data, err = await self.ksspi.authenticate('KERBEROS', '','cifs/%s' % self.settings.target, 3, flags.value, authdata = authData) if err is not None: return None, None, err self.session_key, err = await self.ksspi.get_sessionkey() if err is not None: return None, None, err aprep = AP_REP.load(data).native subkey = Key(aprep['enc-part']['etype'], self.session_key) self.gssapi = get_gssapi(subkey) if aprep['enc-part']['etype'] != 23: #no need for seq number in rc4 raw_seq_data, err = await self.ksspi.get_sequenceno() if err is not None: return None, None, err self.seq_number = GSSWrapToken.from_bytes(raw_seq_data[16:]).SND_SEQ self.iterations += 1 await self.ksspi.disconnect() return data, False, None else: raise Exception('SSPI Kerberos -RPC - auth encountered too many calls for authenticate.') else: status, ctxattr, apreq, err = await self.ksspi.authenticate('KERBEROS', '','cifs/%s' % self.settings.target, 3, flags.value, authdata = b'') if err is not None: return None, None, err self.session_key, err = await self.ksspi.get_sessionkey() if err is not None: raise err await self.ksspi.disconnect() return apreq, False, None except Exception as e: return None, None, e
async def authenticate(self, authData=None, flags=None, seq_number=0, is_rpc=False): #authdata is only for api compatibility reasons if is_rpc == True: if self.iterations == 0: flags = ISC_REQ.CONFIDENTIALITY | \ ISC_REQ.INTEGRITY | \ ISC_REQ.MUTUAL_AUTH | \ ISC_REQ.REPLAY_DETECT | \ ISC_REQ.SEQUENCE_DETECT|\ ISC_REQ.USE_DCE_STYLE token = self.ksspi.get_ticket_for_spn(self.target, flags=flags, is_rpc=True, token_data=authData) #print(token.hex()) self.iterations += 1 return token, True elif self.iterations == 1: flags = ISC_REQ.USE_DCE_STYLE token = self.ksspi.get_ticket_for_spn(self.target, flags=flags, is_rpc=True, token_data=authData) #print(token.hex()) aprep = AP_REP.load(token).native subkey = Key(aprep['enc-part']['etype'], self.get_session_key()) cipher_text = aprep['enc-part']['cipher'] cipher = _enctype_table[aprep['enc-part']['etype']]() plaintext = cipher.decrypt(subkey, 12, cipher_text) self.gssapi = get_gssapi(subkey) self.iterations += 1 return token, False else: raise Exception( 'SSPI Kerberos -RPC - auth encountered too many calls for authenticate.' ) else: apreq = self.ksspi.get_ticket_for_spn(self.target) return apreq, False
async def authenticate(self, authData = None, flags = None, seq_number = 0, is_rpc = False): #authdata is only for api compatibility reasons if self.ksspi is None: await self.start_remote_kerberos() try: if is_rpc == True: if self.iterations == 0: flags = ISC_REQ.CONFIDENTIALITY | \ ISC_REQ.INTEGRITY | \ ISC_REQ.MUTUAL_AUTH | \ ISC_REQ.REPLAY_DETECT | \ ISC_REQ.SEQUENCE_DETECT|\ ISC_REQ.USE_DCE_STYLE apreq, res = await self.ksspi.authenticate('cifs/%s' % self.settings.target, flags = str(flags.value)) self.iterations += 1 return apreq, True, None elif self.iterations == 1: data, err = await self.ksspi.authenticate('cifs/%s' % self.settings.target, flags = str(flags.value), token_data = authData) if err is not None: return None, None, err self.session_key, err = await self.ksspi.get_session_key() if err is not None: return None, None, err aprep = AP_REP.load(data).native subkey = Key(aprep['enc-part']['etype'], self.session_key) self.gssapi = get_gssapi(subkey) if aprep['enc-part']['etype'] != 23: #no need for seq number in rc4 raw_seq_data, err = await self.ksspi.get_seq_number() if err is not None: return None, None, err self.seq_number = GSSWrapToken.from_bytes(raw_seq_data[16:]).SND_SEQ self.iterations += 1 await self.ksspi.disconnect() return data, False, None else: raise Exception('SSPI Kerberos -RPC - auth encountered too many calls for authenticate.') else: apreq, res = await self.ksspi.authenticate('cifs/%s' % self.settings.target) #print('MULTIPLEXOR KERBEROS SSPI, APREQ: %s ERROR: %s' % (apreq, res)) if res is None: self.session_key, res = await self.ksspi.get_session_key() await self.ksspi.disconnect() return apreq, res, None except Exception as e: return None, None, err
def from_buffer(buff): t = PKU2U_TOKEN() t_hdr = buff.tell() buff.read(1) # 0x60 total_length = cl_buff(buff) buff.read(1) # 0x06 total_length += buff.tell() - t_hdr - 1 oid_length = cl_buff(buff) t_oid = buff.read(oid_length) t.tok_id = PKU2U_TOKEN_TYPE(buff.read(2)) t_data = buff.read(total_length - buff.tell()) #t.inner_token_raw = t_data if t.tok_id == PKU2U_TOKEN_TYPE.KRB_AS_REQ: t.inner_token = AS_REQ.load(t_data) elif t.tok_id == PKU2U_TOKEN_TYPE.KRB_AS_REP: t.inner_token = AS_REP.load(t_data) elif t.tok_id == PKU2U_TOKEN_TYPE.KRB_AP_REQ: t.inner_token = AP_REQ.load(t_data) elif t.tok_id == PKU2U_TOKEN_TYPE.KRB_AP_REP: t.inner_token = AP_REP.load(t_data) else: t.inner_token = t_data return t
async def authenticate(self, authData, flags=None, seq_number=0, is_rpc=False): try: if self.kc is None: _, err = await self.setup_kc() if err is not None: return None, None, err if self.iterations == 0: try: #check TGS first, maybe ccache already has what we need for target in self.ccred.ccache.list_targets(): # just printing this to debug... logger.debug('CCACHE target SPN record: %s' % target) tgs, encpart, self.session_key = await self.kc.get_TGS( self.spn) self.from_ccache = True except Exception as e: # this is normal when no credentials stored in ccache #tgt = await self.kc.get_TGT(override_etype=[18]) tgt = await self.kc.get_TGT() tgs, encpart, self.session_key = await self.kc.get_TGS( self.spn) ap_opts = [] if is_rpc == True: if self.iterations == 0: ap_opts.append('mutual-required') flags = ChecksumFlags.GSS_C_CONF_FLAG | ChecksumFlags.GSS_C_INTEG_FLAG | ChecksumFlags.GSS_C_SEQUENCE_FLAG|\ ChecksumFlags.GSS_C_REPLAY_FLAG | ChecksumFlags.GSS_C_MUTUAL_FLAG | ChecksumFlags.GSS_C_DCE_STYLE if self.from_ccache is False: apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) else: apreq = self.kc.construct_apreq_from_ticket( Ticket(tgs['ticket']).dump(), self.session_key, tgs['crealm'], tgs['cname']['name-string'][0], flags=flags, seq_number=seq_number, ap_opts=ap_opts, cb_data=None) self.iterations += 1 return apreq, False, None else: #mutual authentication part here self.seq_number = seq_number aprep = AP_REP.load(authData).native cipher = _enctype_table[int(aprep['enc-part']['etype'])]() cipher_text = aprep['enc-part']['cipher'] temp = cipher.decrypt(self.session_key, 12, cipher_text) enc_part = EncAPRepPart.load(temp).native cipher = _enctype_table[int( enc_part['subkey']['keytype'])]() now = datetime.datetime.now(datetime.timezone.utc) apreppart_data = {} apreppart_data['cusec'] = now.microsecond apreppart_data['ctime'] = now.replace(microsecond=0) apreppart_data['seq-number'] = enc_part['seq-number'] #print('seq %s' % enc_part['seq-number']) apreppart_data_enc = cipher.encrypt( self.session_key, 12, EncAPRepPart(apreppart_data).dump(), None) #overriding current session key self.session_key = Key(cipher.enctype, enc_part['subkey']['keyvalue']) ap_rep = {} ap_rep['pvno'] = 5 ap_rep['msg-type'] = MESSAGE_TYPE.KRB_AP_REP.value ap_rep['enc-part'] = EncryptedData({ 'etype': self.session_key.enctype, 'cipher': apreppart_data_enc }) token = AP_REP(ap_rep).dump() self.gssapi = get_gssapi(self.session_key) self.iterations += 1 return token, False, None else: if self.from_ccache is False: apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) else: apreq = self.kc.construct_apreq_from_ticket( Ticket(tgs['ticket']).dump(), self.session_key, tgs['crealm'], tgs['cname']['name-string'][0], flags=flags, seq_number=seq_number, ap_opts=ap_opts, cb_data=None) return apreq, False, None except Exception as e: return None, None, e
async def authenticate(self, authData, flags=None, seq_number=0, cb_data=None): """ This function is called (multiple times depending on the flags) to perform authentication. """ try: if self.kc is None: _, err = await self.setup_kc() if err is not None: return None, None, err if self.iterations == 0: self.seq_number = 0 #int.from_bytes(os.urandom(4), byteorder='big', signed=False) self.iterations += 1 #tgt = await self.kc.get_TGT() tgt = await self.kc.get_TGT( override_etype=self.preferred_etypes) tgs, encpart, self.session_key = await self.kc.get_TGS( self.spn) #, override_etype = self.preferred_etypes) #self.expected_server_seq_number = encpart.get('nonce', seq_number) ap_opts = [] if ChecksumFlags.GSS_C_MUTUAL_FLAG in self.flags or ChecksumFlags.GSS_C_DCE_STYLE in self.flags: if ChecksumFlags.GSS_C_MUTUAL_FLAG in self.flags: ap_opts.append('mutual-required') apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=self.flags, seq_number=self.seq_number, ap_opts=ap_opts, cb_data=cb_data) return apreq, True, None else: #no mutual or dce auth will take one step only apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=self.flags, seq_number=self.seq_number, ap_opts=[], cb_data=cb_data) self.gssapi = get_gssapi(self.session_key) return apreq, False, None else: self.iterations += 1 #raise Exception('Not implemented!') if ChecksumFlags.GSS_C_DCE_STYLE in self.flags: # adata = authData[16:] # if ChecksumFlags.GSS_C_DCE_STYLE in self.flags: # adata = authData raise Exception('DCE auth Not implemented!') # at this point we are dealing with mutual authentication # This means that the server sent back an AP-rep wrapped in a token # The APREP contains a new session key we'd need to update and a seq-number # that is expected the server will use for future communication. # For mutual auth we dont need to reply anything after this step, # but for DCE auth a reply is expected. TODO # converting the token to aprep token = KRB5_MECH_INDEP_TOKEN.from_bytes(authData) if token.data[:2] != b'\x02\x00': raise Exception('Unexpected token type! %s' % token.data[:2].hex()) aprep = AP_REP.load(token.data[2:]).native # decrypting aprep cipher = _enctype_table[int(aprep['enc-part']['etype'])]() cipher_text = aprep['enc-part']['cipher'] temp = cipher.decrypt(self.session_key, 12, cipher_text) enc_part = EncAPRepPart.load(temp).native #updating session key, gssapi self.session_key = Key(int(enc_part['subkey']['keytype']), enc_part['subkey']['keyvalue']) #self.seq_number = enc_part.get('seq-number', 0) self.gssapi = get_gssapi(self.session_key) return b'', False, None except Exception as e: return None, None, e
async def authenticate(self, authData, flags=None, seq_number=0, is_rpc=False): if self.iterations == 0: #tgt = await self.kc.get_TGT(override_etype=[18]) tgt = await self.kc.get_TGT() tgs, encpart, self.session_key = await self.kc.get_TGS(self.spn) ap_opts = [] if is_rpc == True: if self.iterations == 0: ap_opts.append('mutual-required') flags = ChecksumFlags.GSS_C_CONF_FLAG | ChecksumFlags.GSS_C_INTEG_FLAG | ChecksumFlags.GSS_C_SEQUENCE_FLAG|\ ChecksumFlags.GSS_C_REPLAY_FLAG | ChecksumFlags.GSS_C_MUTUAL_FLAG | ChecksumFlags.GSS_C_DCE_STYLE apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) self.iterations += 1 return apreq, False else: #mutual authentication part here aprep = AP_REP.load(authData).native cipher = _enctype_table[int(aprep['enc-part']['etype'])]() cipher_text = aprep['enc-part']['cipher'] temp = cipher.decrypt(self.session_key, 12, cipher_text) enc_part = EncAPRepPart.load(temp).native cipher = _enctype_table[int(enc_part['subkey']['keytype'])]() now = datetime.datetime.now(datetime.timezone.utc) apreppart_data = {} apreppart_data['cusec'] = now.microsecond apreppart_data['ctime'] = now.replace(microsecond=0) apreppart_data['seq-number'] = enc_part['seq-number'] apreppart_data_enc = cipher.encrypt( self.session_key, 12, EncAPRepPart(apreppart_data).dump(), None) #overriding current session key self.session_key = Key(cipher.enctype, enc_part['subkey']['keyvalue']) ap_rep = {} ap_rep['pvno'] = 5 ap_rep['msg-type'] = MESSAGE_TYPE.KRB_AP_REP.value ap_rep['enc-part'] = EncryptedData({ 'etype': self.session_key.enctype, 'cipher': apreppart_data_enc }) token = AP_REP(ap_rep).dump() self.gssapi = get_gssapi(self.session_key) self.iterations += 1 return token, False else: apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) return apreq, False
async def authenticate(self, authData=None, flags=None, seq_number=0, cb_data=None): """ This function is called (multiple times depending on the flags) to perform authentication. """ try: if self.iterations == 0: self.ksspi = KerberosMSLDAPSSPI(domain=self.domain, username=self.username, password=self.password) token, self.actual_ctx_flags = self.ksspi.get_ticket_for_spn( self.spn, ctx_flags=self.flags) self.iterations += 1 if ISC_REQ.MUTUAL_AUTH in self.actual_ctx_flags or ISC_REQ.USE_DCE_STYLE in self.actual_ctx_flags: #in these cases continuation is needed return token, True, None else: #no mutual or dce auth will take one step only _, err = self.get_session_key() if err is not None: return None, None, err apreq = AP_REQ.load(token).native subkey = Key(apreq['ticket']['enc-part']['etype'], self.session_key) self.gssapi = get_gssapi(subkey) self.get_seq_number() return token, False, None else: adata = authData[16:] if ISC_REQ.USE_DCE_STYLE in self.actual_ctx_flags: adata = authData token, self.actual_ctx_flags = self.ksspi.get_ticket_for_spn( self.spn, ctx_flags=self.actual_ctx_flags, token_data=adata) if ISC_REQ.USE_DCE_STYLE in self.actual_ctx_flags: #Using DCE style 3-legged auth aprep = AP_REP.load(token).native else: aprep = AP_REP.load(adata).native subkey = Key(aprep['enc-part']['etype'], self.get_session_key()) _, err = self.get_session_key() if err is not None: return None, None, err _, err = self.get_seq_number() if err is not None: return None, None, err subkey = Key(token['enc-part']['etype'], self.session_key) self.gssapi = get_gssapi(subkey) self.iterations += 1 return token, False, None except Exception as e: return None, None, e
async def authenticate(self, authData=None, flags=None, seq_number=0, is_rpc=False): #authdata is only for api compatibility reasons if self.operator is None: self.operator = MPNOPerator(self.settings.get_url()) asyncio.create_task(self.operator.run()) await asyncio.wait_for(self.operator.connected_evt.wait(), timeout=self.settings.timeout) if self.ksspi is None: self.ksspi, err = await self.operator.create_sspi(self.agent_id) if err is not None: return None, None, err try: if is_rpc == True: if self.iterations == 0: flags = ISC_REQ.CONFIDENTIALITY | \ ISC_REQ.INTEGRITY | \ ISC_REQ.MUTUAL_AUTH | \ ISC_REQ.REPLAY_DETECT | \ ISC_REQ.SEQUENCE_DETECT|\ ISC_REQ.USE_DCE_STYLE context_attributes, apreq, err = await self.ksspi.kerberos( 'cifs/%s' % self.settings.target, context_attributes=flags.value) if err is not None: raise err self.iterations += 1 return apreq, True, None elif self.iterations == 1: context_attributes, data, err = await self.ksspi.kerberos( target_name='cifs/%s' % self.settings.target, context_attributes=flags.value, token_data=authData) if err is not None: return None, None, err self.session_key, err = await self.ksspi.get_sessionkey() if err is not None: return None, None, err aprep = AP_REP.load(data).native subkey = Key(aprep['enc-part']['etype'], self.session_key) self.gssapi = get_gssapi(subkey) if aprep['enc-part'][ 'etype'] != 23: #no need for seq number in rc4 raw_seq_data, err = await self.ksspi.get_sequenceno() if err is not None: return None, None, err self.seq_number = GSSWrapToken.from_bytes( raw_seq_data[16:]).SND_SEQ self.iterations += 1 await self.ksspi.disconnect() return data, False, None else: raise Exception( 'SSPI Kerberos -RPC - auth encountered too many calls for authenticate.' ) else: context_attributes, apreq, err = await self.ksspi.kerberos( target_name='cifs/%s' % self.settings.target) #print('MULTIPLEXOR KERBEROS SSPI, APREQ: %s ERROR: %s' % (apreq, res)) if err is not None: raise err self.session_key, err = await self.ksspi.get_sessionkey() if err is not None: raise err await self.ksspi.disconnect() return apreq, False, None except Exception as e: return None, None, err