def tgs_from_ccache(self, spn_user, override_etype): try: if self.ccache is None: raise Exception('No CCACHE file found') for tgs, keystruct in self.ccache.get_all_tgs(): ticket_for = ('/'.join(tgs['ticket']['sname']['name-string']) ) + '@' + tgs['ticket']['realm'] if self.usercreds.ccache_spn_strict_check is True: if ticket_for.upper() == str(spn_user).upper(): logger.debug('Found TGS for user %s' % ticket_for) key = Key(keystruct['keytype'], keystruct['keyvalue']) tgs = TGS_REP(tgs).native return tgs, tgs['enc-part'], key, None else: # I hope you know what you are doing at this point... key = Key(keystruct['keytype'], keystruct['keyvalue']) tgs = TGS_REP(tgs).native return tgs, tgs['enc-part'], key, None logger.debug('No TGS found for user %s' % ticket_for) raise Exception('No TGS found for user %s' % ticket_for) except Exception as e: return None, None, None, e
def decrypt_asrep(self, as_rep): def truncate_key(value, keysize): output = b'' currentNum = 0 while len(output) < keysize: currentDigest = hashlib.sha1(bytes([currentNum]) + value).digest() if len(output) + len(currentDigest) > keysize: output += currentDigest[:keysize - len(output)] break output += currentDigest currentNum += 1 return output for pa in as_rep['padata']: if pa['padata-type'] == 17: pkasrep = PA_PK_AS_REP.load(pa['padata-value']).native break else: raise Exception('PA_PK_AS_REP not found!') sd = cms.SignedData.load(pkasrep['dhSignedData']).native keyinfo = sd['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 = self.diffie.exchange(pubkey) server_nonce = pkasrep['serverDHNonce'] fullKey = shared_key + self.diffie.dh_nonce + server_nonce etype = as_rep['enc-part']['etype'] cipher = _enctype_table[etype] if etype == Enctype.AES256: t_key = truncate_key(fullKey, 32) elif etype == Enctype.AES128: t_key = truncate_key(fullKey, 16) elif etype == Enctype.RC4: raise NotImplementedError( 'RC4 key truncation documentation missing. it is different from AES' ) #t_key = truncate_key(fullKey, 16) key = Key(cipher.enctype, t_key) enc_data = as_rep['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 encasrep, session_key, cipher
def decrypt_fast_as_rep(armor_key_bytes, computer_subkey_bytes): asrep_data = bytes.fromhex( '6b8207333082072fa003020105a10302010ba282015b3082015730820153a10402020088a282014904820145a08201413082013da082013930820135a003020112a282012c04820128b481f8034f43c667939a3a0a8459c05163929b8d3e7e95f5ac52a285766281a4e5fa9c8961cd4588b651b8ca518203b326049e8ee73faa619bd06473d98fe22f6f0ae2e3adf4a40794ed83d9b4821d3268352e0a1ff24624bbdb58f91f71230b3cdf26a69b4219791343eef6c8473ea6263531ddf54256537bdde322b0fc18838f4a5399cd812fbd972595c75db02e078dc2a2f53335b7d824176d96d0abc5a1f26559667b6dcc180c0321d68222dfdc0dc15d325c33d1536f97e6c8a53e1b7d421884cc6ea64e2f4689621179121394e9e97fda6072cfd34d9f32025672d8f0ecce9bf7ec9e2144dea29673cd2cba5491c47c8603ba05a894fa92ffa1d758109d60f05b2c984a918d4d0830a732eb3aaddb967483588d918794f6a9f38da74b0415d3866e1abd94a30b1b09544553542e434f5250a4133011a003020101a10a30081b0676696374696da58204306182042c30820428a003020105a10b1b09544553542e434f5250a21e301ca003020102a11530131b066b72627467741b09544553542e434f5250a38203f2308203eea003020112a103020102a28203e0048203dce5f6db8e3c92a1f857ed0002a7ed9a30f85ef0aa9e08560e0128b17508ca36eda097ac98266da80129d578bd8af033b8378db62d256a50e665f0cdcf8175eb5fcf9a37fe101ecf816c6206595ac612b52680cf2a29aed78b68b56aae12c3367a79d5f3dd973d8cefb6ebc53ed9e1768ebb71e11f980ee75818bd86cdcd8213c1b12314b592429ea0975adc70cff2e871e12f60ecf8c1a05b95c280be491eb61bf5bab8603e9e60a8eafd16650deaac640a4f26de115d2837e1078a758129bc2d479c63534b44dfebbbdbfc8e5002017c46a1d1bd6066d7d28e902bb4b59800f9dcac9dd3a39d47d413daaf5f97e19ae125a9e547122b04abb7b05d4d72bafbd154c5407d7caa8d861e2ea64ee0fdcc8f1d777734f32cdad37898049bcc23c84968101738e887678238099d21ab14e10562d6c11933ff288394a4e3f501a078faff41eea0567262f304842796a913a6d3e4c845cd7f919da7702ea4077a71acac00778ce2994a10acc38bc9a1f88dc86f8646a08877af8708404d5bebf180986a9518d40e3f8bbffd324372617531f9a541b1f12c25fe680e29d5e6ea7cf4efca55848c9719f880099bfda9d8363db1847ad570cc9d110cce8fbd1073adea8a1d000482930c07e91e9e1791dc85caf267ea9a6dd69151ad8d542aca85ed3cb106eed8f173acddb7313b71a99f9cb490ec98cbd38e18504db29ae0f3b5d14602593730e9e5acacc49b892e7257dcf01cf68d08f921e9ae2c8ebbe790887a2038505f00f8fd9281581415096450a591af4f993b10f11dbf74598614e706664ba398b065f9263f0fd92e210575c647b3571147e207f3af51cd990a6bdfb501de55a15e6be55c63435bfc8336dfb367a7ea9b0673bfaafe9eeb67fd3e78aa5fd57f662449ce2be1032693504b3277da419a2dc20c28d3481bd4e2a02a3a23bfd690634cd596b22a34af1514c9a28ae8daa5757ad25a8d9f871ea5b9ea613171e1949f322045309877fa930cf5cb39c144e960b7e2a27d5a1dac8e7857c0cdc5548502b9352c0d3d71ba7a24a1fb3bc8dcf5786750abf8b57caeca7e9854e84c3fd85fe561c78568879191e29388d246185d4e9fd9e85907a71830bbe63a7270ad68523f940507ae322a7750c5f3aeda561b1bb3aed043557fc5023b1eba66db649753bb3099a9fde06be697c743a0954825c5ae4b3eab89ba86893365b65a9267f3b0c52a0198952512d12d044f47db039b0feba44f0d4cdc2c2aaab9dd86c568c73afa48d518e3e22b208d48d712554f11eedc5af8df587352d521dcb1c7bc52533f4752b477f922021777c014648853090202df6c7bcdd15329e83eb0688e0dafd0e7f4dcd5a5c27c9f2c1ea2d84d952a46c63398400b2d84ca322ea9b5a682016c30820168a003020112a103020103a282015a048201560efd8839a038e5399968a534391f82ce15d602d3195d26c7bcc6d954980c1fe80cb83d220610553a87e352899542077e4cd431b2cb0e4944eae0c8c85c3e7214a479220c84da70c4a48d8b4dc3ea8c9da34ee36c775b7b30a227c311f2a5ed8046a98d87d2ae113fbc37c0283a46ea50ba9bc0f33d902f7649350b6120ff794e3f6a4608f3ec482fe45001b442958bed6da03a5518a701180f49c215edd8a1c38865a33cff928bb1b82819986326bb572122cc9f7bdab019175a73c0b3aa85df44e1ca2c1d516eeeba17443ea28d019136bef31d6b14a600db9d8211ba9827ba54fc1df68286060dff2a89bd4653c0b18a135d15dd922bc390cadd0c5fe7592ad97bdd1387c5269351bcaa4f6043cd3cad3fbbd577648ee2d9e32711c24d1739e004b1241b9d7caa1007c3d81999a01238362a7d680153301c6562aa523b8673afc5571d96c3afad8e01f390ef14d48dc2843182eab9' ) asrep = AS_REP.load(asrep_data).native encfastrep = None for padata in asrep['padata']: if padata['padata-type'] == 136: armoreddata = PA_FX_FAST_REPLY.load(padata['padata-value']).native encfastrep = armoreddata['enc-fast-rep'] cipherText = encfastrep['cipher'] armor_key = Key(_enctype_table[encfastrep['etype']].enctype, armor_key_bytes) krbfastrep_dec_data = _enctype_table[encfastrep['etype']].decrypt( armor_key, 52, cipherText) krbfastrep_dec = KrbFastResponse.load(krbfastrep_dec_data).native pprint(krbfastrep_dec) print('krbfastrep_dec sucsess dec') strengthen_key = Key( _enctype_table[krbfastrep_dec['strengthen-key']['keytype']].enctype, krbfastrep_dec['strengthen-key']['keyvalue']) computer_subkey = Key( _enctype_table[krbfastrep_dec['strengthen-key']['keytype']].enctype, computer_subkey_bytes) #dunno_key = cf2(krbfastrep_dec['strengthen-key']['keytype'], strengthen_key, computer_subkey, b"strengthenkey", b"replykey") cipherText = asrep['enc-part']['cipher'] ku = None for i in range(100): try: armor_key = Key(_enctype_table[encfastrep['etype']].enctype, armor_key) tgt_encpart = _enctype_table[encfastrep['etype']].decrypt( strengthen_key, i, cipherText) tgt_encpart_dec = EncTGSRepPart.load(tgt_encpart).native ku = i pprint(tgt_encpart_dec) input() except: continue input(ku) return krbfastrep_dec['strengthen-key'][ 'keyvalue'], krbfastrep_dec, armor_key
def tgt_from_ccache(self, override_etype=None): try: if self.ccache is None: raise Exception('No CCACHE file found') our_user = str( self.usercreds.username) + '@' + self.usercreds.domain for tgt, keystruct in self.ccache.get_all_tgt(): ticket_for = tgt['cname']['name-string'][0] + '@' + tgt[ 'crealm'] if ticket_for.upper() == our_user.upper(): logger.debug('Found TGT for user %s' % our_user) self.kerberos_TGT = tgt self.kerberos_TGT_encpart = tgt['enc-part'] self.kerberos_session_key = Key(keystruct['keytype'], keystruct['keyvalue']) self.kerberos_cipher = _enctype_table[keystruct['keytype']] self.kerberos_cipher_type = keystruct['keytype'] return True, None logger.debug('No TGT found for user %s' % our_user) raise Exception('No TGT found for user %s' % our_user) except Exception as e: return None, e
def decrypt_fast_as_req(session_key): #### trying to decrpyt the AS-REQ with user's password + tgt subkey key from the machine account client_as_req = bytes.fromhex( '6a8207903082078ca103020105a20302010aa38206d3308206cf308206cba10402020088a28206c1048206bda08206b9308206b5a08205323082052ea003020101a1820525048205216e82051d30820519a003020105a10302010ea20703050000000000a38204586182045430820450a003020105a10b1b09544553542e434f5250a21e301ca003020102a11530131b066b72627467741b09544553542e434f5250a382041a30820416a003020112a103020102a2820408048204048c76c7670f689ef1742dedd3c16c0043521cf2a3ca5f6fef84b760e97a452ef70ad69d028cd0c0aa1d0692421b74f7c102d338e35ebcba3d96554bc013a3f23d841cc570506d457acd7a519e79c32fc3ac443b687599be74ce59346aba831983d8da4a24e5c1d8d0758bae89cc34ecdd1754e51bb527c7171086897faa611b6f5f501eebf0a488cd4b07e0c7859c67cc000dce6b9c8945c3ead8d6786663ab585b30e86f51935e6ac5a0c813c567d03d2d9a6ad7b67d2f77098582bd80e0c81c1367f865f41a027d628ac4874036e0face8362c2375fedabcbf6ca98a02dd693cfa96d840367b15a02a3582abbee29d70a55d785f50370fc0e1b6ba349dc3c79d498fbc46ce4f3947ae94c4d9f5c2791ec4824835c55f34983aa30cb22d892b4764f4746c8e9231ada10c9eb3dfdb3ad21c89102d009539164e5f64b79490605954f5298bcf7eaedb1498620a5f06f075be7f1d6ca22a4a788a9af7e4f8ee4202951a5511d62b99177893102c5654b7cdd3d402b44105fe4daaca98429cac4eb51fa7879512427a813db032a610724ea8648263f592c2f4dd934f2b7e53419c75b371e6a7dc9636d2538a8cd74e36041e8755c018eb9d51b1f4e5ea25db3c576c8a9db7b6c019f9ae550f0704b2eaaae489bf42274217982063fc6498fe638698feab668a8f4a189dc7b762bc79eda23be1afbee6717930dca827d270d220a265d7dc25d31ca54b24e518c5f6a95ed3b53adc4512838d63c75d037b75049fc604f92620e46f1a9ba49fae3015c0431c57e7981bb7a97f3115ea865206ada7300e2ff1c87728c587fb64f6d31ef746623d454bafb54fb451eb5bdae84ef445483a255f20eb28a345afc245f8fea7eefca583379c2935b9f6b31c759a2ca1b1d7df33c86b187e56aa8dd6edb139bc4d26a53cce1d236a18276e32c135d05fbc36e3d9c310cb36892fc2c9d7716bb3fae2b788986869d92af5379d5e5e334b00b31bbc0f7f1957051c144b45f297a0bb2ce07c1f65d57931662cc3aea530bc4f0228c6653effde024e0a4096ba5e0ad5b8964a2042733ce290c36e604820a6f9be00aa4652f119a0972763ed264d45675b10cc025633fcf873d10bc2855086e8beaf428c6ee9f16e93718477f21b643eb2459b5222587395e8d5da9f6d31ffee7088295e65de747823e74da93df9a35eabbf93f7267ea79f0557fb8896f9004af99f42aed55510d169bbabd3e0bd4c517fa30bb396e31182685479ef96b78146a40597927d62d9fc044d257b63e7db6977598871f755ef36b5b9ff4b9ef1e6cb2255a51c57f408f89df9ad50b7ef2d243ca86b0fe0376c47813e305463d6aa081e70ee9f4f677934f74018b8d0a701e4d4c080ae61b698d78b3a5bb116035b52c0575878bb29b4b91848e84844b6e7118086e639ace845bc028cac48c8765fcf0970ee045a2a481a73081a4a003020112a2819c048199f363e352e88f51743ffa449016a24aeab84f4be14dc24216bfa48837cc4c0c3327580a0caa498e8674d283711bae53eceb367b03e39b3975fb76b820f053f5c2830bdc2fc672d30be07fce88a7bfad85ad5f1470594db2c61b725223103eb3a08de787d3eabbc9a395eb4fabe3062dde554fa8825629fd395903377a095e64c58e22d114aea20741d1717c394353f8696888b4b9308bd1f4e1a1173015a003020110a10e040c5783dcf20fb734229e49def5a28201623082015ea003020112a282015504820151883af50c6bc8bd5ba10a4ed6688ad248057271a5b06405639631c7ca00311f005f6932155536d5e80ed9ef398589703a24c6093415d8c7e1b5a6bd0c47f501b290e6ca0d9f0d8dd3d61fc04090dae610e4e92cbfd9b1568dfb80058a76897065a262ffca403c62b7442ce419936a3b7a8581cbb3f61e09fa0d5dc1f0d9444fb65f3090013d1377a8438e0de04a8c81805131e882985e112204639bcc24ef66624a31b8121fdc3c357b2c389f98523d1ffbeae85a38a3b461cdd6160f518faf86b9f83f95cfe8217dcae43c062405328791368d84674eea1c3d32801e38e96fde33fbb8cff068149b3d668b0720ec3bd90a69fb77965f6b092c4d93f7bc341a1abef7c1bda73680251ddc7f58643a92108ce7fdcfe07e0ae4f12f751b1a1d01b1d450699df65a2fcfb9144ca25ad45bf5eec2402166978114526ff97d5e05b5f0487a612bab979d00cfe08ee5e3e5ea7b5aa481a83081a5a00703050040810010a1133011a003020101a10a30081b0676696374696da2061b0454455354a3193017a003020102a110300e1b066b72627467741b0454455354a511180f32303337303931333032343830355aa611180f32303337303931333032343830355aa706020461d2923ea81530130201120201110201170201180202ff79020103a91d301b3019a003020114a11204104f56455250524f544543544544202020' ) client_as_req_native = AS_REQ.load(client_as_req).native encfastreq = None armor_native = None # at this point this is a AS_REP ticket which was obtained using the machine account. This ticket is used here to identify the correct sub-key to be used. for padata in client_as_req_native['padata']: if padata['padata-type'] == 136: armoreddata = PA_FX_FAST_REQUEST.load( padata['padata-value']).native encfastreq = armoreddata['enc-fast-req'] armortype = armoreddata['armor']['armor-type'] if armortype != 1: raise Exception('AS_REQ must have armortype = 1') armor_native = AP_REQ.load( armoreddata['armor']['armor-value']).native #### First we need to obtain the subkey from the 'armor' part of the PA-FX-FAST PADATA section. This is actually an AP_REQ structure that holds the Authenticator (encrypted with the TGT session key recieved using the machine account) which holds the subkey. This subkey is used together with the machine account session key to form the armorkey. authenticator = decrypt_authenticator( armor_native['authenticator']['etype'], armor_native['authenticator']['cipher'], session_key) computer_subkey_type = authenticator['subkey']['keytype'] computer_subkey_bytes = authenticator['subkey']['keyvalue'] #### now that we have the subkey, we can create the armor-key and using it we can decrypt the KrbFastReq structure which will contain the (normal) AS_REQ with the encrypted timestamp used for preauth cipherText = encfastreq['cipher'] computer_session_key = Key(_enctype_table[encfastreq['etype']].enctype, session_key) client_authenticator_subkey = Key( _enctype_table[encfastreq['etype']].enctype, computer_subkey_bytes) armor_key = cf2(encfastreq['etype'], client_authenticator_subkey, computer_session_key, b"subkeyarmor", b"ticketarmor") krbfastreq_dec_data = _enctype_table[encfastreq['etype']].decrypt( armor_key, 51, cipherText) krbfastreq_dec = KrbFastReq.load(krbfastreq_dec_data).native pprint(krbfastreq_dec) print('krbfastreq_dec sucsess dec') return armor_key.contents, decrypt_fast_as_req
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
def get_tgt(self, target=None): if target is None: logon = get_logon_info() if logon['logonserver'] is None: raise Exception( 'Failed to get logonserver and no target was specified! This wont work.' ) target = 'cifs/%s' % logon['logonserver'] ctx = AcquireCredentialsHandle(None, 'kerberos', target, SECPKG_CRED.OUTBOUND) res, ctx, data, outputflags, expiry = InitializeSecurityContext( ctx, target, token=None, ctx=ctx, flags=ISC_REQ.DELEGATE | ISC_REQ.MUTUAL_AUTH | ISC_REQ.ALLOCATE_MEMORY) if res == SEC_E.OK or res == SEC_E.CONTINUE_NEEDED: #key_data = sspi._get_session_key() raw_ticket = self.export_ticketdata_target(0, target) key = Key(raw_ticket['Key']['KeyType'], raw_ticket['Key']['Key']) token = InitialContextToken.load(data[0][1]) ticket = AP_REQ(token.native['innerContextToken']).native cipher = _enctype_table[ticket['authenticator']['etype']] dec_authenticator = cipher.decrypt( key, 11, ticket['authenticator']['cipher']) authenticator = Authenticator.load(dec_authenticator).native if authenticator['cksum']['cksumtype'] != 0x8003: raise Exception('Checksum not good :(') checksum_data = AuthenticatorChecksum.from_bytes( authenticator['cksum']['checksum']) if ChecksumFlags.GSS_C_DELEG_FLAG not in checksum_data.flags: raise Exception('delegation flag not set!') cred_orig = KRB_CRED.load(checksum_data.delegation_data).native dec_authenticator = cipher.decrypt(key, 14, cred_orig['enc-part']['cipher']) #info = EncKrbCredPart.load(dec_authenticator).native #reconstructing kirbi with the unencrypted data te = {} te['etype'] = 0 te['cipher'] = dec_authenticator ten = EncryptedData(te) t = {} t['pvno'] = cred_orig['pvno'] t['msg-type'] = cred_orig['msg-type'] t['tickets'] = cred_orig['tickets'] t['enc-part'] = ten cred = KRB_CRED(t) return cred.dump()
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
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
def from_tgt(target, tgt, key): """ Sets up the kerberos object from tgt and the session key. Use this function when pulling the TGT from ccache file. """ kc = KerbrosClient(None, target) kc.kerberos_TGT = tgt kc.kerberos_cipher_type = key['keytype'] kc.kerberos_session_key = Key(kc.kerberos_cipher_type, key['keyvalue']) kc.kerberos_cipher = _enctype_table[kc.kerberos_cipher_type] return kc
def decrypt_authenticator(authenticator_enc_type, authenticator_enc_data, key_bytes, key_usage=11): cipherText = authenticator_enc_data kerberos_key = Key(_enctype_table[authenticator_enc_type].enctype, key_bytes) authenticator_data_dec = _enctype_table[authenticator_enc_type].decrypt( kerberos_key, key_usage, cipherText) authenticator_dec_native = Authenticator.load( authenticator_data_dec).native return authenticator_dec_native
def build_asreq_lts(self, supported_encryption_method, kdcopts = ['forwardable','renewable','proxiable']): 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() logger.debug('Selecting common encryption type: %s' % supported_encryption_method.name) self.kerberos_cipher = _enctype_table[supported_encryption_method.value] self.kerberos_cipher_type = supported_encryption_method.value self.kerberos_key = Key(self.kerberos_cipher.enctype, self.usercreds.get_key_for_enctype(supported_encryption_method, 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': supported_encryption_method.value, 'cipher': enc_timestamp}).dump() kdc_req_body = {} kdc_req_body['kdc-options'] = KDCOptions(set(kdcopts)) 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'] = [supported_encryption_method.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) return AS_REQ(kdc_req)
async def authenticate(self, authData=None, flags=None, seq_number=0, cb_data=None): #authdata is only for api compatibility reasons if self.ksspi is None: await self.start_remote_kerberos() try: apreq, res = await self.ksspi.authenticate( self.settings.target.to_target_string(), flags=str(self.flags.value)) #print('MULTIPLEXOR KERBEROS SSPI, APREQ: %s ERROR: %s' % (apreq, res)) if res is not None: return None, None, res # here it seems like we get the full token not just the apreq data... # so we need to discard the layers self.session_key, err = await self.ksspi.get_session_key() if err is not None: return None, None, err unwrap = KRB5_MECH_INDEP_TOKEN.from_bytes(apreq) aprep = AP_REQ.load(unwrap.data[2:]).native subkey = Key(aprep['ticket']['enc-part']['etype'], self.session_key) self.gssapi = get_gssapi(subkey) if aprep['ticket']['enc-part']['etype'] != 23: 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 return unwrap.data[2:], False, res except Exception as e: return None, None, e
async def authenticate(self, authData=None, flags=None, seq_number=0, cb_data=None): try: status, ctxattr, apreq, err = await self.sspi.authenticate( 'KERBEROS', '', self.settings.target.to_target_string(), 3, self.flags.value, authdata=b'') if err is not None: raise err self.flags = ISC_REQ(ctxattr) self.session_key, err = await self.sspi.get_sessionkey() if err is not None: return None, None, err unwrap = KRB5_MECH_INDEP_TOKEN.from_bytes(apreq) aprep = AP_REQ.load(unwrap.data[2:]).native subkey = Key(aprep['ticket']['enc-part']['etype'], self.session_key) self.gssapi = get_gssapi(subkey) if aprep['ticket']['enc-part']['etype'] != 23: if ISC_REQ.CONFIDENTIALITY in self.flags: raw_seq_data, err = await self.sspi.get_sequenceno() if err is not None: return None, None, err self.seq_number = GSSWrapToken.from_bytes( raw_seq_data[16:]).SND_SEQ return unwrap.data[2:], False, None except Exception as e: return None, None, e
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
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
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] 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') return self.ksoc.sendrecv(req.dump())
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
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','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) logger.debug('[S4U2proxy] Sending request to server') try: reply = self.ksoc.sendrecv(req.dump()) except KerberosError as e: if e.errorcode.value == 16: logger.error('S4U2proxy: Failed to get S4U2proxy! Error code (16) indicates that delegation is not enabled for this account! Full error: %s' % e) raise e 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
asrep_4_native = KerberosResponse.load(asrep_4).native pprint(asrep_4_native) cred = KerberosCredential() cred.username = '******' cred.domain = 'TEST.corp' #cred.password = '******' cred.kerberos_key_aes_256 = '7289306c73ca8909cf89bc01afe3e29f26211f89d922fb317cc5d81cfdf8465d' supp_enc = EncryptionType.AES256_CTS_HMAC_SHA1_96 cipherText = asrep_4_native['enc-part']['cipher'] print(cipherText.hex()) key_bytes = cred.get_key_for_enctype(supp_enc, None) kerberos_key = Key(_enctype_table[asrep_4_native['enc-part']['etype']].enctype, key_bytes) temp = _enctype_table[asrep_4_native['enc-part']['etype']].decrypt(kerberos_key, 3, cipherText) temp_dec = EncASRepPart.load(temp).native pprint(temp_dec) computer_session_key_bytes = temp_dec['key']['keyvalue'] #### decrypting authenticator (it's in the second AP_REQ message FAST data's armor section that is for the user) #### includes a ticket with an authenticator data = bytes.fromhex('6e82051d30820519a003020105a10302010ea20703050000000000a38204586182045430820450a003020105a10b1b09544553542e434f5250a21e301ca003020102a11530131b066b72627467741b09544553542e434f5250a382041a30820416a003020112a103020102a2820408048204048c76c7670f689ef1742dedd3c16c0043521cf2a3ca5f6fef84b760e97a452ef70ad69d028cd0c0aa1d0692421b74f7c102d338e35ebcba3d96554bc013a3f23d841cc570506d457acd7a519e79c32fc3ac443b687599be74ce59346aba831983d8da4a24e5c1d8d0758bae89cc34ecdd1754e51bb527c7171086897faa611b6f5f501eebf0a488cd4b07e0c7859c67cc000dce6b9c8945c3ead8d6786663ab585b30e86f51935e6ac5a0c813c567d03d2d9a6ad7b67d2f77098582bd80e0c81c1367f865f41a027d628ac4874036e0face8362c2375fedabcbf6ca98a02dd693cfa96d840367b15a02a3582abbee29d70a55d785f50370fc0e1b6ba349dc3c79d498fbc46ce4f3947ae94c4d9f5c2791ec4824835c55f34983aa30cb22d892b4764f4746c8e9231ada10c9eb3dfdb3ad21c89102d009539164e5f64b79490605954f5298bcf7eaedb1498620a5f06f075be7f1d6ca22a4a788a9af7e4f8ee4202951a5511d62b99177893102c5654b7cdd3d402b44105fe4daaca98429cac4eb51fa7879512427a813db032a610724ea8648263f592c2f4dd934f2b7e53419c75b371e6a7dc9636d2538a8cd74e36041e8755c018eb9d51b1f4e5ea25db3c576c8a9db7b6c019f9ae550f0704b2eaaae489bf42274217982063fc6498fe638698feab668a8f4a189dc7b762bc79eda23be1afbee6717930dca827d270d220a265d7dc25d31ca54b24e518c5f6a95ed3b53adc4512838d63c75d037b75049fc604f92620e46f1a9ba49fae3015c0431c57e7981bb7a97f3115ea865206ada7300e2ff1c87728c587fb64f6d31ef746623d454bafb54fb451eb5bdae84ef445483a255f20eb28a345afc245f8fea7eefca583379c2935b9f6b31c759a2ca1b1d7df33c86b187e56aa8dd6edb139bc4d26a53cce1d236a18276e32c135d05fbc36e3d9c310cb36892fc2c9d7716bb3fae2b788986869d92af5379d5e5e334b00b31bbc0f7f1957051c144b45f297a0bb2ce07c1f65d57931662cc3aea530bc4f0228c6653effde024e0a4096ba5e0ad5b8964a2042733ce290c36e604820a6f9be00aa4652f119a0972763ed264d45675b10cc025633fcf873d10bc2855086e8beaf428c6ee9f16e93718477f21b643eb2459b5222587395e8d5da9f6d31ffee7088295e65de747823e74da93df9a35eabbf93f7267ea79f0557fb8896f9004af99f42aed55510d169bbabd3e0bd4c517fa30bb396e31182685479ef96b78146a40597927d62d9fc044d257b63e7db6977598871f755ef36b5b9ff4b9ef1e6cb2255a51c57f408f89df9ad50b7ef2d243ca86b0fe0376c47813e305463d6aa081e70ee9f4f677934f74018b8d0a701e4d4c080ae61b698d78b3a5bb116035b52c0575878bb29b4b91848e84844b6e7118086e639ace845bc028cac48c8765fcf0970ee045a2a481a73081a4a003020112a2819c048199f363e352e88f51743ffa449016a24aeab84f4be14dc24216bfa48837cc4c0c3327580a0caa498e8674d283711bae53eceb367b03e39b3975fb76b820f053f5c2830bdc2fc672d30be07fce88a7bfad85ad5f1470594db2c61b725223103eb3a08de787d3eabbc9a395eb4fabe3062dde554fa8825629fd395903377a095e64c58e22d114aea20741d1717c394353f8696888b4b9308bd1f4e1')
def S4U2self(self, user_to_impersonate, 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 krb_tgs_body = {} krb_tgs_body['kdc-options'] = KDCOptions(set(['forwardable','renewable','canonicalize'])) krb_tgs_body['sname'] = PrincipalName({'name-type': NAME_TYPE.UNKNOWN.value, 'name-string': [self.usercreds.username]}) 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') try: reply = self.ksoc.sendrecv(req.dump()) except KerberosError as e: if e.errorcode.value == 16: logger.error('[S4U2self] Failed to get S4U2self! Error code (16) indicates that delegation is not enabled for this account! Full error: %s' % e) raise e 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 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
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, 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.iteractions == 0: self.setup() self.iteractions += 1 #authdata should be 0 at this point if self.is_azure is True: # kerberos service is on the same ip asreq = self.pkinit.build_asreq(target = self.target.get_hostname_or_ip(), kdcopts = ['forwardable','renewable','proxiable', 'canonicalize']) else: if self.target.dc_ip is None: raise Exception('DC IP must be set for kerberos auth!') asreq = self.pkinit.build_asreq(kdcopts = ['forwardable','renewable','proxiable', 'canonicalize']) negodata = generate_init_nego(self._msgctr, self._convid) self._msgctr += 1 metadata = self.__get_metadata() self._msgctr += 1 ap_req, token_raw = generate_ap_req(self._msgctr, self._convid, asreq, PKU2U_TOKEN_TYPE.KRB_AS_REQ) self._krb_finished_data += token_raw # for the checksum calc... self._msgctr += 1 msg = negodata + metadata + ap_req self._msgs += msg return msg, True, None elif self.iteractions == 1: from minikerberos.protocol.encryption import Enctype, _checksum_table, _enctype_table, Key self.iteractions += 1 self._msgs += authData msgs = negoexts_parse_bytes(authData) self._msgctr += len(msgs) #print(msgs[MESSAGE_TYPE.CHALLENGE].Exchange.inner_token.native) as_rep = msgs[MESSAGE_TYPE.CHALLENGE].Exchange.inner_token.native self._krb_finished_data += msgs[MESSAGE_TYPE.CHALLENGE].exchange_data_raw # for the checksum calc... encasrep, session_key, cipher = self.pkinit.decrypt_asrep(as_rep) self.xxxxx = session_key self.session_key_data = {} self.session_key_data['keytype'] = Enctype.AES256 self.session_key_data['keyvalue'] = os.urandom(32) subkey_cipher = _enctype_table[self.session_key_data['keytype']] subkey_key = Key(subkey_cipher.enctype, self.session_key_data['keyvalue']) subkey_checksum = _checksum_table[16] # ChecksumTypes.hmac_sha1_96_aes256 ap_req = self.pkinit.build_apreq(as_rep, session_key, cipher, self.session_key_data, self._krb_finished_data) ap_req_msg, _ = generate_ap_req(self._msgctr, self._convid, ap_req, PKU2U_TOKEN_TYPE.KRB_AP_REQ) #print(ap_req_msg.hex()) self._msgctr += 1 checksum_final = subkey_checksum.checksum(subkey_key, 25, self._msgs + ap_req_msg ) verify_msg = generate_verify(self._msgctr, self._convid, checksum_final, 16) self._msgctr += 1 ret_msg = ap_req_msg + verify_msg self._msgs += ret_msg return ret_msg, True, None elif self.iteractions == 2: from minikerberos.protocol.encryption import Enctype, _checksum_table, _enctype_table, Key from minikerberos.protocol.asn1_structs import EncAPRepPart #input('aaaaaaaaaaaaaa') self.iteractions += 1 self._msgs += authData msgs = negoexts_parse_bytes(authData) self._msgctr += len(msgs) ap_rep = msgs[MESSAGE_TYPE.CHALLENGE].Exchange.inner_token.native #print(ap_rep) #self.xxxxx cipher = _enctype_table[int(ap_rep['enc-part']['etype'])]() cipher_text = ap_rep['enc-part']['cipher'] subkey_key = Key(cipher.enctype, self.xxxxx.contents) temp = cipher.decrypt(subkey_key, 12, cipher_text) enc_part = EncAPRepPart.load(temp).native #print(enc_part) cipher = _enctype_table[int(enc_part['subkey']['keytype'])]() self.session_key = Key(cipher.enctype, enc_part['subkey']['keyvalue']) self.gssapi = get_gssapi(self.session_key) return None, False, None
def build_apreq(self, asrep, session_key, cipher, subkey_data, krb_finished_data, flags=GSSAPIFlags.GSS_C_MUTUAL_FLAG | GSSAPIFlags.GSS_C_INTEG_FLAG | GSSAPIFlags.GSS_C_EXTENDED_ERROR_FLAG): # TODO: https://www.ietf.org/rfc/rfc4757.txt #subkey_data = {} #subkey_data['keytype'] = Enctype.AES256 #subkey_data['keyvalue'] = os.urandom(32) subkey_cipher = _enctype_table[subkey_data['keytype']] subkey_key = Key(subkey_cipher.enctype, subkey_data['keyvalue']) subkey_checksum = _checksum_table[ 16] # ChecksumTypes.hmac_sha1_96_aes256 krb_finished_checksum_data = {} krb_finished_checksum_data['cksumtype'] = 16 krb_finished_checksum_data['checksum'] = subkey_checksum.checksum( subkey_key, 41, krb_finished_data) krb_finished_data = {} krb_finished_data['gss-mic'] = Checksum(krb_finished_checksum_data) krb_finished = KRB_FINISHED(krb_finished_data).dump() a = 2 extensions_data = a.to_bytes( 4, byteorder='big', signed=True) + len(krb_finished).to_bytes( 4, byteorder='big', signed=True) + krb_finished ac = AuthenticatorChecksum() ac.flags = flags ac.channel_binding = b'\x00' * 16 chksum = {} chksum['cksumtype'] = 0x8003 chksum['checksum'] = ac.to_bytes() + extensions_data tii = LSAP_TOKEN_INFO_INTEGRITY() tii.Flags = 1 tii.TokenIL = 0x00002000 # Medium integrity tii.MachineID = bytes.fromhex( '7e303fffe6bff25146addca4fbddf1b94f1634178eb4528fb2731c669ca23cde') restriction_data = {} restriction_data['restriction-type'] = 0 restriction_data['restriction'] = tii.to_bytes() restriction_data = KERB_AD_RESTRICTION_ENTRY(restriction_data) x = KERB_AD_RESTRICTION_ENTRYS([restriction_data]).dump() restrictions = AuthorizationData([{ 'ad-type': 141, 'ad-data': x }]).dump() now = datetime.datetime.now(datetime.timezone.utc) authenticator_data = {} authenticator_data['authenticator-vno'] = krb5_pvno authenticator_data['crealm'] = Realm(asrep['crealm']) authenticator_data['cname'] = asrep['cname'] authenticator_data['cusec'] = now.microsecond authenticator_data['ctime'] = now.replace(microsecond=0) authenticator_data['subkey'] = EncryptionKey(subkey_data) authenticator_data['seq-number'] = 682437742 #??? TODO: check this! authenticator_data['authorization-data'] = AuthorizationData([{ 'ad-type': 1, 'ad-data': restrictions }]) authenticator_data['cksum'] = Checksum(chksum) #print('Authenticator(authenticator_data).dump()') #print(Authenticator(authenticator_data).dump().hex()) authenticator_data_enc = cipher.encrypt( session_key, 11, Authenticator(authenticator_data).dump(), None) ap_opts = ['mutual-required'] ap_req = {} ap_req['pvno'] = krb5_pvno ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value ap_req['ticket'] = Ticket(asrep['ticket']) ap_req['ap-options'] = APOptions(set(ap_opts)) ap_req['authenticator'] = EncryptedData({ 'etype': session_key.enctype, 'cipher': authenticator_data_enc }) #pprint('AP_REQ \r\n%s' % AP_REQ(ap_req).native) #print(AP_REQ(ap_req).dump().hex()) #input() return AP_REQ(ap_req).dump()
def get_TGS(self, spn_user, override_etype = None, is_linux = False): """ Requests a TGS ticket for the specified user. Returns 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 """ logger.debug('[getTGS] Constructing 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('[getTGS] Constructing request to server') rep = self.ksoc.sendrecv(req.dump()) logger.debug('[getTGS] Got 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('[getTGS] Got valid reply') self.kerberos_TGS = tgs return tgs, encTGSRepPart, key