def sendrecv(self, data, throw=True): #throw variable indicates wether to create an exception when a kerberos error happens or just return the kerberos error" #for any other exceptions types (eg. connection related errors) an exception will be raised regardless self.create_soc() try: if self.soc_type == KerberosSocketType.TCP: length = len(data).to_bytes(4, byteorder='big', signed=False) self.soc.sendall(length + data) buff = b'' total_length = -1 while True: temp = b'' temp = self.soc.recv(4096) if temp == b'': break buff += temp if total_length == -1: if len(buff) > 4: total_length = int.from_bytes(buff[:4], byteorder='big', signed=False) if total_length == 0: raise Exception( 'Returned data length is 0! This means the server did not understand our message' ) if total_length != -1: if len(buff) == total_length + 4: buff = buff[4:] break elif len(buff) > total_length + 4: raise Exception('Got too much data somehow') else: continue elif self.soc_type == KerberosSocketType.UDP: self.soc.sendto(data, (self.dst_ip, self.dst_port)) while True: buff, addr = self.soc.recvfrom(65535) if addr[0] == self.dst_ip: break else: # got a message from a different IP than the target, strange! # continuing, but this might result in an infinite loop continue if buff == b'': raise Exception('Server closed the connection!') krb_message = KerberosResponse.load(buff) if krb_message.name == 'KRB_ERROR' and throw == True: raise KerberosError(krb_message) return krb_message finally: self.soc.close()
def do_preauth(self, supported_encryption_method, kdcopts = ['forwardable','renewable','renewable-ok']): if self.usercreds.certificate is not None: req = self.build_asreq_pkinit(supported_encryption_method, kdcopts) else: req = self.build_asreq_lts(supported_encryption_method, kdcopts) logger.debug('Sending TGT request to server') rep = self.ksoc.sendrecv(req.dump()) if rep.name == 'KRB_ERROR': raise KerberosError(rep, 'Preauth failed!') return rep
def decrypt_pk_dh(data, diffieHellmanExchange): try: rep = SPNEGO_PKINIT_AS_REP.load(bytes.fromhex(data)).native except: krb_message = KerberosResponse.load(bytes.fromhex(data)) raise KerberosError(krb_message) relevantPadata = None for padata in rep['Kerberos']['padata']: if padata['padata-type'] == 17: relevantPadata = PA_PK_AS_REP.load(padata['padata-value']).native break if not relevantPadata: raise Exception('No PAdata found with type 17') keyinfo = SignedData.load( relevantPadata['dhSignedData']).native['encap_content_info'] if keyinfo['content_type'] != '1.3.6.1.5.2.3.2': raise Exception('Keyinfo content type unexpected value') authdata = KDCDHKeyInfo.load(keyinfo['content']).native pubkey = int( ''.join(['1'] + [str(x) for x in authdata['subjectPublicKey']]), 2) pubkey = int.from_bytes(core.BitString( authdata['subjectPublicKey']).dump()[7:], 'big', signed=False) shared_key = diffieHellmanExchange.exchange(pubkey) server_nonce = relevantPadata['serverDHNonce'] fullKey = shared_key + diffieHellmanExchange.dh_nonce + server_nonce etype = rep['Kerberos']['enc-part']['etype'] cipher = _enctype_table[etype] if etype == Enctype.AES256: t_key = truncate(fullKey, 32) elif etype == Enctype.AES128: t_key = truncate(fullKey, 16) elif etype == Enctype.RC4: raise NotImplementedError( 'RC4 key truncation documentation missing. it is different from AES' ) key = Key(cipher.enctype, t_key) enc_data = rep['Kerberos']['enc-part']['cipher'] dec_data = cipher.decrypt(key, 3, enc_data) encasrep = EncASRepPart.load(dec_data).native cipher = _enctype_table[int(encasrep['key']['keytype'])] session_key = Key(cipher.enctype, encasrep['key']['keyvalue']) return session_key, cipher, rep # remove Octet String manualy padata = str(rep['padata'][0]['padata-value']).encode('hex') parsedPadata = decode(padata.decode('hex'), asn1Spec=AS_REP_Padata())[0] decoded = parsedPadata['DHRepInfo']['dhSignedData'] kdcSignedDataResponse = decode(decoded, asn1Spec=SignedData())[0] kdcDHKeyInfo = str(kdcSignedDataResponse['encapContentInfo'] ['id-pkinit-authData-value']).encode('hex') d = decode(kdcDHKeyInfo.decode('hex'), asn1Spec=KDCDHKeyInfo())[0] dcPublicKey = int(encode(d['subjectPublicKey']).encode('hex')[20:], 16) dcPublicNumbers = dh.DHPublicNumbers(dcPublicKey, diffieHellmanExchange[2]) backend = default_backend() dcPublicKey = backend.load_dh_public_numbers(dcPublicNumbers) shared_key = diffieHellmanExchange[1].exchange(dcPublicKey) sharedHexKey = shared_key.encode('hex') clientDHNonce = '6B328FA66EEBDFD3D69ED34E5007776AB30832A2ED1DCB1699781BFE0BEDF87A' serverDHNonce = encode( parsedPadata['DHRepInfo']['encKeyPack']).encode('hex')[8:] fullKey = sharedHexKey + clientDHNonce + serverDHNonce etype = rep['enc-part']['etype'] cipher = _enctype_table[etype] if etype == Enctype.AES256: truncateKey = truncate(fullKey, 32) key = Key(cipher.enctype, truncateKey) elif etype == Enctype.AES128: truncateKey = truncate(fullKey, 16) key = Key(cipher.enctype, truncateKey) elif etype == Enctype.RC4: truncateKey = truncate(fullKey, 16) key = Key(cipher.enctype, truncateKey) cipherText = rep['enc-part']['cipher'].asOctets() plainText = cipher.decrypt(key, 3, cipherText) encASRepPart = decode(plainText, asn1Spec=EncASRepPart())[0] cipher = _enctype_table[int(encASRepPart['key']['keytype'])] session_key = Key(cipher.enctype, encASRepPart['key']['keyvalue'].asOctets()) return session_key, cipher, rep
def get_TGT(self, override_etype = None, decrypt_tgt = True): """ decrypt_tgt: used for asreproast attacks Steps performed: 1. Send and empty (no encrypted timestamp) AS_REQ with all the encryption types we support 2. Depending on the response (either error or AS_REP with TGT) we either send another AS_REQ with the encrypted data or return the TGT (or fail miserably) 3. PROFIT """ logger.debug('[getTGT] Generating initial TGT without authentication data') now = datetime.datetime.now(datetime.timezone.utc) kdc_req_body = {} kdc_req_body['kdc-options'] = KDCOptions(set(['forwardable','renewable','proxiable'])) kdc_req_body['cname'] = PrincipalName({'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': [self.usercreds.username]}) kdc_req_body['realm'] = self.usercreds.domain.upper() kdc_req_body['sname'] = PrincipalName({'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': ['krbtgt', self.usercreds.domain.upper()]}) kdc_req_body['till'] = (now + datetime.timedelta(days=1)).replace(microsecond=0) kdc_req_body['rtime'] = (now + datetime.timedelta(days=1)).replace(microsecond=0) kdc_req_body['nonce'] = secrets.randbits(31) if override_etype is None: kdc_req_body['etype'] = self.usercreds.get_supported_enctypes() else: kdc_req_body['etype'] = override_etype pa_data_1 = {} pa_data_1['padata-type'] = int(PADATA_TYPE('PA-PAC-REQUEST')) pa_data_1['padata-value'] = PA_PAC_REQUEST({'include-pac': True}).dump() kdc_req = {} kdc_req['pvno'] = krb5_pvno kdc_req['msg-type'] = MESSAGE_TYPE.KRB_AS_REQ.value kdc_req['padata'] = [pa_data_1] kdc_req['req-body'] = KDC_REQ_BODY(kdc_req_body) req = AS_REQ(kdc_req) logger.debug('[getTGT] Sending initial TGT to %s' % self.ksoc.get_addr_str()) rep = self.ksoc.sendrecv(req.dump(), throw = False) if rep.name != 'KRB_ERROR': #user can do kerberos auth without preauthentication! self.kerberos_TGT = rep.native etype = self.kerberos_TGT['enc-part']['etype'] #if we want to roast the asrep (tgt rep) part then we dont even have the proper keys to decrypt #so we just return, the asrep can be extracted from this object anyhow if decrypt_tgt == False: return self.kerberos_cipher = _enctype_table[etype] self.kerberos_cipher_type = etype encryption_type = EncryptionType(self.kerberos_cipher.enctype) enctype = self.usercreds.get_key_for_enctype(encryption_type) self.kerberos_key = Key(self.kerberos_cipher.enctype, enctype) else: if rep.native['error-code'] != KerberosErrorCode.KDC_ERR_PREAUTH_REQUIRED.value: raise KerberosError(rep) rep = rep.native logger.debug('[getTGT] Got reply from server, asking to provide auth data') rep = self.do_preauth(rep) logger.debug('[getTGT] Got valid response from server') rep = rep.native self.kerberos_TGT = rep cipherText = self.kerberos_TGT['enc-part']['cipher'] temp = self.kerberos_cipher.decrypt(self.kerberos_key, 3, cipherText) try: self.kerberos_TGT_encpart = EncASRepPart.load(temp).native except Exception as e: logger.debug('[getTGT] EncAsRepPart load failed, is this linux?') try: self.kerberos_TGT_encpart = EncTGSRepPart.load(temp).native except Exception as e: logger.error('[getTGT] Failed to load decrypted part of the reply!') raise e self.kerberos_session_key = Key(self.kerberos_cipher.enctype, self.kerberos_TGT_encpart['key']['keyvalue']) self.ccache.add_tgt(self.kerberos_TGT, self.kerberos_TGT_encpart, override_pp = True) logger.debug('[getTGT] Got valid TGT') return
async def S4U2proxy( self, s4uself_ticket, spn_user, supp_enc_methods=[ EncryptionType.DES_CBC_CRC, EncryptionType.DES_CBC_MD4, EncryptionType.DES_CBC_MD5, EncryptionType.DES3_CBC_SHA1, EncryptionType.ARCFOUR_HMAC_MD5, EncryptionType.AES256_CTS_HMAC_SHA1_96, EncryptionType.AES128_CTS_HMAC_SHA1_96 ]): logger.debug('[S4U2proxy] Impersonating %s' % '/'.join(spn_user.get_principalname())) now = datetime.datetime.now(datetime.timezone.utc) supp_enc = self.usercreds.get_preferred_enctype(supp_enc_methods) pa_pac_opts = {} pa_pac_opts['padata-type'] = int(PADATA_TYPE('PA-PAC-OPTIONS')) pa_pac_opts['padata-value'] = PA_PAC_OPTIONS({ 'value': PA_PAC_OPTIONSTypes(set(['resource-based constrained delegation'])) }).dump() authenticator_data = {} authenticator_data['authenticator-vno'] = krb5_pvno authenticator_data['crealm'] = Realm(self.kerberos_TGT['crealm']) authenticator_data['cname'] = self.kerberos_TGT['cname'] authenticator_data['cusec'] = now.microsecond authenticator_data['ctime'] = now.replace(microsecond=0) authenticator_data_enc = self.kerberos_cipher.encrypt( self.kerberos_session_key, 7, Authenticator(authenticator_data).dump(), None) ap_req = {} ap_req['pvno'] = krb5_pvno ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value ap_req['ap-options'] = APOptions(set()) ap_req['ticket'] = Ticket(self.kerberos_TGT['ticket']) ap_req['authenticator'] = EncryptedData({ 'etype': self.kerberos_cipher_type, 'cipher': authenticator_data_enc }) pa_tgs_req = {} pa_tgs_req['padata-type'] = PaDataType.TGS_REQ.value pa_tgs_req['padata-value'] = AP_REQ(ap_req).dump() krb_tgs_body = {} #krb_tgs_body['kdc-options'] = KDCOptions(set(['forwardable','forwarded','renewable','renewable-ok', 'canonicalize'])) krb_tgs_body['kdc-options'] = KDCOptions( set([ 'forwardable', 'renewable', 'constrained-delegation', 'canonicalize' ])) krb_tgs_body['sname'] = PrincipalName({ 'name-type': NAME_TYPE.SRV_INST.value, 'name-string': spn_user.get_principalname() }) krb_tgs_body['realm'] = self.usercreds.domain.upper() krb_tgs_body['till'] = (now + datetime.timedelta(days=1)).replace( microsecond=0) krb_tgs_body['nonce'] = secrets.randbits(31) krb_tgs_body['etype'] = [ supp_enc.value ] #selecting according to server's preferences krb_tgs_body['additional-tickets'] = [s4uself_ticket] krb_tgs_req = {} krb_tgs_req['pvno'] = krb5_pvno krb_tgs_req['msg-type'] = MESSAGE_TYPE.KRB_TGS_REQ.value krb_tgs_req['padata'] = [pa_tgs_req, pa_pac_opts] krb_tgs_req['req-body'] = KDC_REQ_BODY(krb_tgs_body) req = TGS_REQ(krb_tgs_req) reply = await self.ksoc.sendrecv(req.dump()) if reply.name == 'KRB_ERROR': emsg = 'S4U2proxy failed!' if reply.native['error-code'] == 16: emsg = 'S4U2proxy: Failed to get S4U2proxy! Error code (16) indicates that delegation is not enabled for this account!' raise KerberosError(reply, emsg) logger.debug('[S4U2proxy] Got server reply, decrypting...') tgs = reply.native encTGSRepPart = EncTGSRepPart.load( self.kerberos_cipher.decrypt(self.kerberos_session_key, 8, tgs['enc-part']['cipher'])).native key = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue']) self.ccache.add_tgs(tgs, encTGSRepPart) logger.debug('[S4U2proxy] Got valid TGS reply') return tgs, encTGSRepPart, key
async def S4U2self( self, user_to_impersonate, spn_user=None, kdcopts=['forwardable', 'renewable', 'canonicalize'], supp_enc_methods=[ EncryptionType.DES_CBC_CRC, EncryptionType.DES_CBC_MD4, EncryptionType.DES_CBC_MD5, EncryptionType.DES3_CBC_SHA1, EncryptionType.ARCFOUR_HMAC_MD5, EncryptionType.AES256_CTS_HMAC_SHA1_96, EncryptionType.AES128_CTS_HMAC_SHA1_96 ]): """ user_to_impersonate : KerberosTarget class """ if not self.kerberos_TGT: logger.debug('[S4U2self] TGT is not available! Fetching TGT...') self.get_TGT() supp_enc = self.usercreds.get_preferred_enctype(supp_enc_methods) auth_package_name = 'Kerberos' now = datetime.datetime.now(datetime.timezone.utc) ###### Calculating authenticator data authenticator_data = {} authenticator_data['authenticator-vno'] = krb5_pvno authenticator_data['crealm'] = Realm(self.kerberos_TGT['crealm']) authenticator_data['cname'] = self.kerberos_TGT['cname'] authenticator_data['cusec'] = now.microsecond authenticator_data['ctime'] = now.replace(microsecond=0) authenticator_data_enc = self.kerberos_cipher.encrypt( self.kerberos_session_key, 7, Authenticator(authenticator_data).dump(), None) ap_req = {} ap_req['pvno'] = krb5_pvno ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value ap_req['ap-options'] = APOptions(set()) ap_req['ticket'] = Ticket(self.kerberos_TGT['ticket']) ap_req['authenticator'] = EncryptedData({ 'etype': self.kerberos_cipher_type, 'cipher': authenticator_data_enc }) pa_data_auth = {} pa_data_auth['padata-type'] = PaDataType.TGS_REQ.value pa_data_auth['padata-value'] = AP_REQ(ap_req).dump() ###### Calculating checksum data S4UByteArray = NAME_TYPE.PRINCIPAL.value.to_bytes(4, 'little', signed=False) S4UByteArray += user_to_impersonate.username.encode() S4UByteArray += user_to_impersonate.domain.encode() S4UByteArray += auth_package_name.encode() logger.debug('[S4U2self] S4UByteArray: %s' % S4UByteArray.hex()) logger.debug('[S4U2self] S4UByteArray: %s' % S4UByteArray) chksum_data = _HMACMD5.checksum(self.kerberos_session_key, 17, S4UByteArray) logger.debug('[S4U2self] chksum_data: %s' % chksum_data.hex()) chksum = {} chksum['cksumtype'] = int(CKSUMTYPE('HMAC_MD5')) chksum['checksum'] = chksum_data ###### Filling out PA-FOR-USER data for impersonation pa_for_user_enc = {} pa_for_user_enc['userName'] = PrincipalName({ 'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': user_to_impersonate.get_principalname() }) pa_for_user_enc['userRealm'] = user_to_impersonate.domain pa_for_user_enc['cksum'] = Checksum(chksum) pa_for_user_enc['auth-package'] = auth_package_name pa_for_user = {} pa_for_user['padata-type'] = int(PADATA_TYPE('PA-FOR-USER')) pa_for_user['padata-value'] = PA_FOR_USER_ENC(pa_for_user_enc).dump() ###### Constructing body spn_user = [self.usercreds.username] if spn_user is not None: if isinstance(spn_user, str): spn_user = [spn_user] elif isinstance(spn_user, list): spn_user = spn_user else: spn_user = spn_user.get_principalname() krb_tgs_body = {} krb_tgs_body['kdc-options'] = KDCOptions(set(kdcopts)) krb_tgs_body['sname'] = PrincipalName({ 'name-type': NAME_TYPE.UNKNOWN.value, 'name-string': spn_user }) krb_tgs_body['realm'] = self.usercreds.domain.upper() krb_tgs_body['till'] = (now + datetime.timedelta(days=1)).replace( microsecond=0) krb_tgs_body['nonce'] = secrets.randbits(31) krb_tgs_body['etype'] = [ supp_enc.value ] #selecting according to server's preferences krb_tgs_req = {} krb_tgs_req['pvno'] = krb5_pvno krb_tgs_req['msg-type'] = MESSAGE_TYPE.KRB_TGS_REQ.value krb_tgs_req['padata'] = [pa_data_auth, pa_for_user] krb_tgs_req['req-body'] = KDC_REQ_BODY(krb_tgs_body) req = TGS_REQ(krb_tgs_req) logger.debug('[S4U2self] Sending request to server') reply = await self.ksoc.sendrecv(req.dump()) if reply.name == 'KRB_ERROR': emsg = 'S4U2self failed!' if reply.native['error-code'] == 16: emsg = 'S4U2self: Failed to get S4U2self! Error code (16) indicates that delegation is not enabled for this account!' raise KerberosError(reply, emsg) logger.debug('[S4U2self] Got reply, decrypting...') tgs = reply.native encTGSRepPart = EncTGSRepPart.load( self.kerberos_cipher.decrypt(self.kerberos_session_key, 8, tgs['enc-part']['cipher'])).native key = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue']) self.ccache.add_tgs(tgs, encTGSRepPart) logger.debug('[S4U2self] Got valid TGS reply') self.kerberos_TGS = tgs return tgs, encTGSRepPart, key
async def get_TGS(self, spn_user, override_etype=None, is_linux=False): """ Requests a TGS ticket for the specified user. Retruns the TGS ticket, end the decrpyted encTGSRepPart. spn_user: KerberosTarget: the service user you want to get TGS for. override_etype: None or list of etype values (int) Used mostly for kerberoasting, will override the AP_REQ supported etype values (which is derived from the TGT) to be able to recieve whatever tgs tiecket """ #first, let's check if CCACHE has the correct ticket already tgs, encTGSRepPart, key, err = self.tgs_from_ccache( spn_user, override_etype) if err is None: return tgs, encTGSRepPart, key if self.kerberos_TGT is None: #let's check if CCACHE has a TGT for us _, err = self.tgt_from_ccache(override_etype=override_etype) if err is not None: raise Exception('No TGT found in CCACHE!') #nope, we need to contact the server logger.debug('Constructing TGS request for user %s' % spn_user.get_formatted_pname()) now = datetime.datetime.now(datetime.timezone.utc) kdc_req_body = {} kdc_req_body['kdc-options'] = KDCOptions( set(['forwardable', 'renewable', 'renewable_ok', 'canonicalize'])) kdc_req_body['realm'] = spn_user.domain.upper() kdc_req_body['sname'] = PrincipalName({ 'name-type': NAME_TYPE.SRV_INST.value, 'name-string': spn_user.get_principalname() }) kdc_req_body['till'] = (now + datetime.timedelta(days=1)).replace( microsecond=0) kdc_req_body['nonce'] = secrets.randbits(31) if override_etype: kdc_req_body['etype'] = override_etype else: kdc_req_body['etype'] = [self.kerberos_cipher_type] authenticator_data = {} authenticator_data['authenticator-vno'] = krb5_pvno authenticator_data['crealm'] = Realm(self.kerberos_TGT['crealm']) authenticator_data['cname'] = self.kerberos_TGT['cname'] authenticator_data['cusec'] = now.microsecond authenticator_data['ctime'] = now.replace(microsecond=0) if is_linux: ac = AuthenticatorChecksum() ac.flags = 0 ac.channel_binding = b'\x00' * 16 chksum = {} chksum['cksumtype'] = 0x8003 chksum['checksum'] = ac.to_bytes() authenticator_data['cksum'] = Checksum(chksum) authenticator_data['seq-number'] = 0 authenticator_data_enc = self.kerberos_cipher.encrypt( self.kerberos_session_key, 7, Authenticator(authenticator_data).dump(), None) ap_req = {} ap_req['pvno'] = krb5_pvno ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value ap_req['ap-options'] = APOptions(set()) ap_req['ticket'] = Ticket(self.kerberos_TGT['ticket']) ap_req['authenticator'] = EncryptedData({ 'etype': self.kerberos_cipher_type, 'cipher': authenticator_data_enc }) pa_data_1 = {} pa_data_1['padata-type'] = PaDataType.TGS_REQ.value pa_data_1['padata-value'] = AP_REQ(ap_req).dump() kdc_req = {} kdc_req['pvno'] = krb5_pvno kdc_req['msg-type'] = MESSAGE_TYPE.KRB_TGS_REQ.value kdc_req['padata'] = [pa_data_1] kdc_req['req-body'] = KDC_REQ_BODY(kdc_req_body) req = TGS_REQ(kdc_req) logger.debug('Constructing TGS request to server') rep = await self.ksoc.sendrecv(req.dump()) if rep.name == 'KRB_ERROR': raise KerberosError(rep, 'get_TGS failed!') logger.debug('Got TGS reply, decrypting...') tgs = rep.native encTGSRepPart = EncTGSRepPart.load( self.kerberos_cipher.decrypt(self.kerberos_session_key, 8, tgs['enc-part']['cipher'])).native key = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue']) self.ccache.add_tgs(tgs, encTGSRepPart) logger.debug('Got valid TGS reply') self.kerberos_TGS = tgs return tgs, encTGSRepPart, key
async def do_preauth(self, rep): #now getting server's supported encryption methods supp_enc_methods = collections.OrderedDict() for enc_method in METHOD_DATA.load(rep['e-data']).native: data_type = PaDataType(enc_method['padata-type']) if data_type == PaDataType.ETYPE_INFO or data_type == PaDataType.ETYPE_INFO2: if data_type == PaDataType.ETYPE_INFO: enc_info_list = ETYPE_INFO.load(enc_method['padata-value']) elif data_type == PaDataType.ETYPE_INFO2: enc_info_list = ETYPE_INFO2.load( enc_method['padata-value']) for enc_info in enc_info_list.native: supp_enc_methods[EncryptionType( enc_info['etype'])] = enc_info['salt'] logger.debug( 'Server supports encryption type %s with salt %s' % (EncryptionType( enc_info['etype']).name, enc_info['salt'])) logger.debug('Constructing TGT request with auth data') #now to create an AS_REQ with encrypted timestamp for authentication pa_data_1 = {} pa_data_1['padata-type'] = int(PADATA_TYPE('PA-PAC-REQUEST')) pa_data_1['padata-value'] = PA_PAC_REQUEST({ 'include-pac': True }).dump() now = datetime.datetime.now(datetime.timezone.utc) #creating timestamp asn1 timestamp = PA_ENC_TS_ENC({ 'patimestamp': now.replace(microsecond=0), 'pausec': now.microsecond }).dump() supp_enc = self.usercreds.get_preferred_enctype(supp_enc_methods) logger.debug('Selecting common encryption type: %s' % supp_enc.name) self.kerberos_cipher = _enctype_table[supp_enc.value] self.kerberos_cipher_type = supp_enc.value if 'salt' in enc_info and enc_info['salt'] is not None: self.server_salt = enc_info['salt'].encode() self.kerberos_key = Key( self.kerberos_cipher.enctype, self.usercreds.get_key_for_enctype(supp_enc, salt=self.server_salt)) enc_timestamp = self.kerberos_cipher.encrypt(self.kerberos_key, 1, timestamp, None) pa_data_2 = {} pa_data_2['padata-type'] = int(PADATA_TYPE('ENC-TIMESTAMP')) pa_data_2['padata-value'] = EncryptedData({ 'etype': supp_enc.value, 'cipher': enc_timestamp }).dump() kdc_req_body = {} kdc_req_body['kdc-options'] = KDCOptions( set(['forwardable', 'renewable', 'proxiable'])) kdc_req_body['cname'] = PrincipalName({ 'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': [self.usercreds.username] }) kdc_req_body['realm'] = self.usercreds.domain.upper() kdc_req_body['sname'] = PrincipalName({ 'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': ['krbtgt', self.usercreds.domain.upper()] }) kdc_req_body['till'] = (now + datetime.timedelta(days=1)).replace( microsecond=0) kdc_req_body['rtime'] = (now + datetime.timedelta(days=1)).replace( microsecond=0) kdc_req_body['nonce'] = secrets.randbits(31) kdc_req_body['etype'] = [ supp_enc.value ] #selecting according to server's preferences kdc_req = {} kdc_req['pvno'] = krb5_pvno kdc_req['msg-type'] = MESSAGE_TYPE.KRB_AS_REQ.value kdc_req['padata'] = [pa_data_2, pa_data_1] kdc_req['req-body'] = KDC_REQ_BODY(kdc_req_body) req = AS_REQ(kdc_req) logger.debug('Sending TGT request to server') rep = await self.ksoc.sendrecv(req.dump()) if rep.name == 'KRB_ERROR': raise KerberosError(rep, 'Preauth failed!') return rep