def toKRBCRED(self): principal = self.principal credential = self.credentials[0] krbCredInfo = KrbCredInfo() krbCredInfo['key'] = noValue krbCredInfo['key']['keytype'] = credential['key']['keytype'] krbCredInfo['key']['keyvalue'] = credential['key']['keyvalue'] krbCredInfo['prealm'] = principal.realm.fields['data'] krbCredInfo['pname'] = noValue krbCredInfo['pname']['name-type'] = principal.header['name_type'] seq_set_iter(krbCredInfo['pname'], 'name-string', (principal.components[0].fields['data'], )) krbCredInfo['flags'] = credential['tktflags'] krbCredInfo['starttime'] = KerberosTime.to_asn1( datetime.utcfromtimestamp(credential['time']['starttime'])) krbCredInfo['endtime'] = KerberosTime.to_asn1( datetime.utcfromtimestamp(credential['time']['endtime'])) krbCredInfo['renew-till'] = KerberosTime.to_asn1( datetime.utcfromtimestamp(credential['time']['renew_till'])) krbCredInfo['srealm'] = credential['server'].realm.fields['data'] krbCredInfo['sname'] = noValue krbCredInfo['sname']['name-type'] = credential['server'].header[ 'name_type'] tmp_service_class = credential['server'].components[0].fields['data'] tmp_service_hostname = credential['server'].components[1].fields[ 'data'] seq_set_iter(krbCredInfo['sname'], 'name-string', (tmp_service_class, tmp_service_hostname)) encKrbCredPart = EncKrbCredPart() seq_set_iter(encKrbCredPart, 'ticket-info', (krbCredInfo, )) krbCred = KRB_CRED() krbCred['pvno'] = 5 krbCred['msg-type'] = 22 krbCred['enc-part'] = noValue krbCred['enc-part']['etype'] = 0 krbCred['enc-part']['cipher'] = encoder.encode(encKrbCredPart) ticket = decoder.decode(credential.ticket['data'], asn1Spec=Ticket())[0] seq_set_iter(krbCred, 'tickets', (ticket, )) encodedKrbCred = encoder.encode(krbCred) return encodedKrbCred
def convert_kirbi_to_ccache(input_filename, output_filename): with open(input_filename, 'rb') as fi: krb_cred = decoder.decode(fi.read(), asn1Spec=KRB_CRED())[0] enc_krb_cred_part = decoder.decode(krb_cred['enc-part']['cipher'], asn1Spec=EncKrbCredPart())[0] ccache = CCache() ccache.headers = [] header = Header() header['tag'] = 1 header['taglen'] = 8 header['tagdata'] = '\xff\xff\xff\xff\x00\x00\x00\x00' ccache.headers.append(header) krb_cred_info = enc_krb_cred_part['ticket-info'][0] tmpPrincipal = types.Principal() tmpPrincipal.from_asn1(krb_cred_info, 'prealm', 'pname') ccache.principal = Principal() ccache.principal.fromPrincipal(tmpPrincipal) credential = Credential() server = types.Principal() server.from_asn1(krb_cred_info, 'srealm', 'sname') tmpServer = Principal() tmpServer.fromPrincipal(server) credential['client'] = ccache.principal credential['server'] = tmpServer credential['is_skey'] = 0 credential['key'] = KeyBlock() credential['key']['keytype'] = int(krb_cred_info['key']['keytype']) credential['key']['keyvalue'] = str(krb_cred_info['key']['keyvalue']) credential['key']['keylen'] = len(credential['key']['keyvalue']) credential['time'] = Times() # credential['time']['authtime'] = ccache.toTimeStamp(types.KerberosTime.from_asn1(krb_cred_info['authtime'])) credential['time']['starttime'] = ccache.toTimeStamp(types.KerberosTime.from_asn1(krb_cred_info['starttime'])) credential['time']['endtime'] = ccache.toTimeStamp(types.KerberosTime.from_asn1(krb_cred_info['endtime'])) credential['time']['renew_till'] = ccache.toTimeStamp(types.KerberosTime.from_asn1(krb_cred_info['renew-till'])) flags = ccache.reverseFlags(krb_cred_info['flags']) credential['tktflags'] = flags credential['num_address'] = 0 credential.ticket = CountedOctetString() credential.ticket['data'] = encoder.encode(krb_cred['tickets'][0].clone(tagSet=Ticket.tagSet, cloneValueFlag=True)) credential.ticket['length'] = len(credential.ticket['data']) credential.secondTicket = CountedOctetString() credential.secondTicket['data'] = '' credential.secondTicket['length'] = 0 ccache.credentials.append(credential) ccache.saveFile(output_filename)
def fromKRBCRED(self, encodedKrbCred): krbCred = decoder.decode(encodedKrbCred, asn1Spec=KRB_CRED())[0] encKrbCredPart = decoder.decode(krbCred['enc-part']['cipher'], asn1Spec=EncKrbCredPart())[0] krbCredInfo = encKrbCredPart['ticket-info'][0] self.setDefaultHeader() tmpPrincipal = types.Principal() tmpPrincipal.from_asn1(krbCredInfo, 'prealm', 'pname') self.principal = Principal() self.principal.fromPrincipal(tmpPrincipal) credential = Credential() server = types.Principal() server.from_asn1(krbCredInfo, 'srealm', 'sname') tmpServer = Principal() tmpServer.fromPrincipal(server) credential['client'] = self.principal credential['server'] = tmpServer credential['is_skey'] = 0 credential['key'] = KeyBlockV4() credential['key']['keytype'] = int(krbCredInfo['key']['keytype']) credential['key']['keyvalue'] = str( krbCredInfo['key']['keyvalue']).asOctets() credential['key']['keylen'] = len(credential['key']['keyvalue']) credential['time'] = Times() credential['time']['authtime'] = self.toTimeStamp( types.KerberosTime.from_asn1(krbCredInfo['starttime'])) credential['time']['starttime'] = self.toTimeStamp( types.KerberosTime.from_asn1(krbCredInfo['starttime'])) credential['time']['endtime'] = self.toTimeStamp( types.KerberosTime.from_asn1(krbCredInfo['endtime'])) credential['time']['renew_till'] = self.toTimeStamp( types.KerberosTime.from_asn1(krbCredInfo['renew-till'])) flags = self.reverseFlags(krbCredInfo['flags']) credential['tktflags'] = flags credential['num_address'] = 0 credential.ticket = CountedOctetString() credential.ticket['data'] = encoder.encode(krbCred['tickets'][0].clone( tagSet=Ticket.tagSet, cloneValueFlag=True)) credential.ticket['length'] = len(credential.ticket['data']) credential.secondTicket = CountedOctetString() credential.secondTicket['data'] = b'' credential.secondTicket['length'] = 0 self.credentials.append(credential)
def makeccache(rb64): ccachefile = 'out.ccache' creds = decoder.decode(base64.b64decode(rb64), asn1Spec=KRB_CRED())[0] if creds['enc-part']['etype'] != 0: raise Exception('Ticket info is encrypted with cipher other than null') enc_part = decoder.decode(creds['enc-part']['cipher'], asn1Spec=EncKrbCredPart())[0] tinfo = enc_part['ticket-info'] ccache = KrbCredCCache() # Enumerate all for i, tinfo in enumerate(tinfo): ccache.fromKrbCredTicket(creds['tickets'][i], tinfo) return ccache
def kirbi2ccache(kirbifile, ccachefile): with open(kirbifile, 'rb') as infile: data = infile.read() creds = decoder.decode(data, asn1Spec=KRB_CRED())[0] # This shouldn't be encrypted normally if creds['enc-part']['etype'] != 0: raise Exception('Ticket info is encrypted with cipher other than null') enc_part = decoder.decode(creds['enc-part']['cipher'], asn1Spec=EncKrbCredPart())[0] tinfo = enc_part['ticket-info'] ccache = KrbCredCCache() # Enumerate all for i, tinfo in enumerate(tinfo): ccache.fromKrbCredTicket(creds['tickets'][i], tinfo) ccache.saveFile(ccachefile)
def convert_ccache_to_kirbi(input_filename, output_filename): ccache = CCache.loadFile(input_filename) principal = ccache.principal credential = ccache.credentials[0] krb_cred_info = KrbCredInfo() krb_cred_info['key'] = noValue krb_cred_info['key']['keytype'] = credential['key']['keytype'] krb_cred_info['key']['keyvalue'] = credential['key']['keyvalue'] krb_cred_info['prealm'] = principal.realm.fields['data'] krb_cred_info['pname'] = noValue krb_cred_info['pname']['name-type'] = principal.header['name_type'] seq_set_iter(krb_cred_info['pname'], 'name-string', (principal.components[0].fields['data'],)) krb_cred_info['flags'] = credential['tktflags'] # krb_cred_info['authtime'] = KerberosTime.to_asn1(datetime.datetime.fromtimestamp(credential['time']['authtime'])) krb_cred_info['starttime'] = KerberosTime.to_asn1(datetime.datetime.utcfromtimestamp(credential['time']['starttime'])) krb_cred_info['endtime'] = KerberosTime.to_asn1(datetime.datetime.utcfromtimestamp(credential['time']['endtime'])) krb_cred_info['renew-till'] = KerberosTime.to_asn1(datetime.datetime.utcfromtimestamp(credential['time']['renew_till'])) krb_cred_info['srealm'] = credential['server'].realm.fields['data'] krb_cred_info['sname'] = noValue krb_cred_info['sname']['name-type'] = credential['server'].header['name_type'] seq_set_iter(krb_cred_info['sname'], 'name-string', (credential['server'].components[0].fields['data'], credential['server'].realm.fields['data'])) enc_krb_cred_part = EncKrbCredPart() seq_set_iter(enc_krb_cred_part, 'ticket-info', (krb_cred_info,)) encoder.encode(krb_cred_info) krb_cred = KRB_CRED() krb_cred['pvno'] = 5 krb_cred['msg-type'] = 22 krb_cred['enc-part'] = noValue krb_cred['enc-part']['etype'] = 0 krb_cred['enc-part']['cipher'] = encoder.encode(enc_krb_cred_part) ticket = decoder.decode(credential.ticket['data'], asn1Spec=Ticket())[0] seq_set_iter(krb_cred, 'tickets', (ticket,)) with open(output_filename, 'wb') as fo: fo.write(encoder.encode(krb_cred))
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