Example #1
0
    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
Example #2
0
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)
Example #3
0
    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)
Example #4
0
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
Example #5
0
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)
Example #6
0
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))
Example #7
0
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