Ejemplo n.º 1
0
	def construct_apreq(self, tgs, encTGSRepPart, sessionkey, flags = None, seq_number = 0, ap_opts = []):
		now = datetime.datetime.now(datetime.timezone.utc)
		authenticator_data = {}
		authenticator_data['authenticator-vno'] = krb5_pvno
		authenticator_data['crealm'] = Realm(self.kerberos_TGT['crealm'])
		authenticator_data['cname'] = self.kerberos_TGT['cname']
		authenticator_data['cusec'] = now.microsecond
		authenticator_data['ctime'] = now.replace(microsecond=0)
		if flags is not None:
			ac = AuthenticatorChecksum()
			ac.flags = flags
			ac.channel_binding = b'\x00'*16
			
			chksum = {}
			chksum['cksumtype'] = 0x8003
			chksum['checksum'] = ac.to_bytes()
			
			authenticator_data['cksum'] = Checksum(chksum)
			authenticator_data['seq-number'] = seq_number
		
		cipher = _enctype_table[encTGSRepPart['key']['keytype']]
		authenticator_data_enc = cipher.encrypt(sessionkey, 11, Authenticator(authenticator_data).dump(), None)
		
		ap_req = {}
		ap_req['pvno'] = krb5_pvno
		ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value
		ap_req['ticket'] = Ticket(tgs['ticket'])
		ap_req['ap-options'] = APOptions(set(ap_opts))
		ap_req['authenticator'] = EncryptedData({'etype': self.kerberos_cipher_type, 'cipher': authenticator_data_enc})

		return AP_REQ(ap_req).dump()
Ejemplo n.º 2
0
	def construct_apreq_from_ticket(ticket_data, sessionkey, crealm, cname, flags = None, seq_number = 0, ap_opts = []):
		"""
		ticket: bytes of Ticket
		"""
		now = datetime.datetime.now(datetime.timezone.utc)
		authenticator_data = {}
		authenticator_data['authenticator-vno'] = krb5_pvno
		authenticator_data['crealm'] = Realm(crealm)
		authenticator_data['cname'] = PrincipalName({'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': [cname]})
		authenticator_data['cusec'] = now.microsecond
		authenticator_data['ctime'] = now.replace(microsecond=0)
		if flags is not None:
			ac = AuthenticatorChecksum()
			ac.flags = flags
			ac.channel_binding = b'\x00'*16
			
			chksum = {}
			chksum['cksumtype'] = 0x8003
			chksum['checksum'] = ac.to_bytes()
			
			authenticator_data['cksum'] = Checksum(chksum)
			authenticator_data['seq-number'] = seq_number
		
		cipher = _enctype_table[sessionkey.enctype]
		authenticator_data_enc = cipher.encrypt(sessionkey, 11, Authenticator(authenticator_data).dump(), None)
		
		ap_req = {}
		ap_req['pvno'] = krb5_pvno
		ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value
		ap_req['ticket'] = Ticket.load(ticket_data)
		ap_req['ap-options'] = APOptions(set(ap_opts))
		ap_req['authenticator'] = EncryptedData({'etype': sessionkey.enctype, 'cipher': authenticator_data_enc})

		return AP_REQ(ap_req).dump()
Ejemplo n.º 3
0
	def add_tgs(self, tgs_rep, enc_tgs_rep_part, override_pp = False): #from AS_REP
		"""
		Creates credential object from the TGS and adds to the ccache file
		The TGS is the native representation of the asn1 encoded TGS_REP data when the user requests a tgs to a specific service principal with a valid TGT
		
		This function doesn't do decryption of the encrypted part of the tgs_rep object, it is expected that the decrypted XXX is supplied in enc_as_rep_part
		
		override_pp: bool to determine if client principal should be used as the primary principal for the ccache file
		"""
		c = Credential()
		c.client = CCACHEPrincipal.from_asn1(tgs_rep['cname'], tgs_rep['crealm'])
		if override_pp == True:
			self.primary_principal = c.client
		c.server = CCACHEPrincipal.from_asn1(enc_tgs_rep_part['sname'], enc_tgs_rep_part['srealm'])
		c.time = Times.from_asn1(enc_tgs_rep_part)
		c.key = Keyblock.from_asn1(enc_tgs_rep_part['key'])
		c.is_skey = 0 #not sure!
		
		c.tktflags = TicketFlags(enc_tgs_rep_part['flags']).cast(core.IntegerBitString).native
		c.num_address = 0
		c.num_authdata = 0
		c.ticket = CCACHEOctetString.from_asn1(Ticket(tgs_rep['ticket']).dump())
		c.second_ticket = CCACHEOctetString.empty()
		
		self.credentials.append(c)
Ejemplo n.º 4
0
	def to_kirbi(self):
		filename = '%s@%s_%s' % (self.client.to_string() , self.server.to_string(), hashlib.sha1(self.ticket.to_asn1()).hexdigest()[:8])
		krbcredinfo = {}
		krbcredinfo['key'] = EncryptionKey(self.key.to_asn1())
		krbcredinfo['prealm'] = self.client.realm.to_string()
		krbcredinfo['pname'] = self.client.to_asn1()[0]
		krbcredinfo['flags'] = core.IntegerBitString(self.tktflags).cast(TicketFlags)
		if self.time.authtime != 0: #this parameter is not mandatory, and most of the time not present
			krbcredinfo['authtime'] = datetime.datetime.fromtimestamp(self.time.authtime)
		krbcredinfo['starttime'] = datetime.datetime.fromtimestamp(self.time.starttime)
		krbcredinfo['endtime'] = datetime.datetime.fromtimestamp(self.time.endtime)
		if self.time.renew_till != 0: #this parameter is not mandatory, and sometimes it's not present
			krbcredinfo['renew-till'] = datetime.datetime.fromtimestamp(self.time.authtime)
		krbcredinfo['srealm'] = self.server.realm.to_string()
		krbcredinfo['sname'] = self.server.to_asn1()[0]
		
		enc_krbcred = {}
		enc_krbcred['ticket-info'] = [KrbCredInfo(krbcredinfo)]
		
		krbcred = {}
		krbcred['pvno'] = krb5_pvno
		krbcred['msg-type'] = MESSAGE_TYPE.KRB_CRED.value
		krbcred['tickets'] = [Ticket.load(self.ticket.to_asn1())]
		krbcred['enc-part'] = EncryptedData({'etype': EncryptionType.NULL.value, 'cipher': EncKrbCredPart(enc_krbcred).dump()})
	
	
	
		kirbi = KRBCRED(krbcred)
		return kirbi, filename
Ejemplo n.º 5
0
	def get_hashes(self, all_hashes = False):
		"""
		Returns a list of hashes in hashcat-firendly format for tickets with encryption type 23 (which is RC4)
		all_hashes: overrides the encryption type filtering and returns hash for all tickets

		"""
		hashes = []
		for cred in self.credentials:
			res = Ticket.load(cred.ticket.to_asn1()).native
			if int(res['enc-part']['etype']) == 23 or all_hashes == True:
				hashes.append(cred.to_hash())

		return hashes
Ejemplo n.º 6
0
    def to_asn1(self):
        krbcredinfo = {}
        krbcredinfo['key'] = EncryptionKey({
            'keytype': self.KeyType,
            'keyvalue': self.Key
        })
        krbcredinfo['prealm'] = self.AltTargetDomainName
        krbcredinfo['pname'] = PrincipalName({
            'name-type': self.EClientName_type,
            'name-string': self.EClientName
        })
        krbcredinfo['flags'] = core.IntegerBitString(
            self.TicketFlags).cast(TicketFlags)
        krbcredinfo['starttime'] = self.StartTime
        krbcredinfo['endtime'] = self.EndTime
        krbcredinfo['renew-till'] = self.RenewUntil
        krbcredinfo['srealm'] = self.DomainName
        krbcredinfo['sname'] = PrincipalName({
            'name-type': self.ServiceName_type,
            'name-string': self.ServiceName
        })

        enc_krbcred = {}
        enc_krbcred['ticket-info'] = [KrbCredInfo(krbcredinfo)]

        ticket = {}
        ticket['tkt-vno'] = krb5_pvno
        ticket['realm'] = self.DomainName
        ticket['sname'] = PrincipalName({
            'name-type': NAME_TYPE.SRV_INST.value,
            'name-string': self.ServiceName
        })
        ticket['enc-part'] = EncryptedData({
            'etype': self.TicketEncType,
            'kvno': self.TicketKvno,
            'cipher': self.Ticket
        })

        krbcred = {}
        krbcred['pvno'] = krb5_pvno
        krbcred['msg-type'] = MESSAGE_TYPE.KRB_CRED.value
        krbcred['tickets'] = [Ticket(ticket)]
        krbcred['enc-part'] = EncryptedData({
            'etype':
            EncryptionType.NULL.value,
            'cipher':
            EncKrbCredPart(enc_krbcred).dump()
        })

        return KRBCRED(krbcred)
Ejemplo n.º 7
0
	def to_hash(self):
		res = Ticket.load(self.ticket.to_asn1()).native
		tgs_encryption_type    = int(res['enc-part']['etype'])
		t = len(res['sname']['name-string'])
		if t == 1:
			tgs_name_string        = res['sname']['name-string'][0]
		else:
			tgs_name_string        = res['sname']['name-string'][1]
		tgs_realm              = res['realm']
		if tgs_encryption_type == EncryptionType.AES256_CTS_HMAC_SHA1_96.value:
			tgs_checksum           = res['enc-part']['cipher'][-12:]
			tgs_encrypted_data2    = res['enc-part']['cipher'][:-12:]
			return '$krb5tgs$%s$%s$%s$%s$%s' % (tgs_encryption_type,tgs_name_string,tgs_realm, tgs_checksum.hex(), tgs_encrypted_data2.hex() )
		else:
			tgs_checksum           = res['enc-part']['cipher'][:16]
			tgs_encrypted_data2    = res['enc-part']['cipher'][16:]
			return '$krb5tgs$%s$*%s$%s$spn*$%s$%s' % (tgs_encryption_type,tgs_name_string,tgs_realm, tgs_checksum.hex(), tgs_encrypted_data2.hex() )
Ejemplo n.º 8
0
	def to_tgt(self):
		"""
		Returns the native format of an AS_REP message and the sessionkey in EncryptionKey native format
		"""
		enc_part = EncryptedData({'etype': 1, 'cipher': b''})
		
		tgt_rep = {}
		tgt_rep['pvno'] = krb5_pvno
		tgt_rep['msg-type'] = MESSAGE_TYPE.KRB_AS_REP.value
		tgt_rep['crealm'] = self.server.realm.to_string()
		tgt_rep['cname'] = self.client.to_asn1()[0]
		tgt_rep['ticket'] = Ticket.load(self.ticket.to_asn1()).native
		tgt_rep['enc-part'] = enc_part.native

		t = EncryptionKey(self.key.to_asn1()).native
		
		return tgt_rep, t
Ejemplo n.º 9
0
    def add_kirbi(self, krbcred, override_pp=True, include_expired=False):
        c = Credential()
        enc_credinfo = EncKrbCredPart.load(
            krbcred['enc-part']['cipher']).native
        ticket_info = enc_credinfo['ticket-info'][0]
        """
		if ticket_info['endtime'] < datetime.datetime.now(datetime.timezone.utc):
			if include_expired == True:
				logging.debug('This ticket has most likely expired, but include_expired is forcing me to add it to cache! This can cause problems!')
			else:
				logging.debug('This ticket has most likely expired, skipping')
				return
		"""

        c.client = CCACHEPrincipal.from_asn1(ticket_info['pname'],
                                             ticket_info['prealm'])
        if override_pp == True:
            self.primary_principal = c.client

        #yaaaaay 4 additional weirdness!!!!
        #if sname name-string contains a realm as well htne impacket will crash miserably :(
        if len(ticket_info['sname']['name-string']
               ) > 2 and ticket_info['sname']['name-string'][-1].upper(
               ) == ticket_info['srealm'].upper():
            logger.debug('SNAME contains the realm as well, trimming it')
            t = ticket_info['sname']
            t['name-string'] = t['name-string'][:-1]
            c.server = CCACHEPrincipal.from_asn1(t, ticket_info['srealm'])
        else:
            c.server = CCACHEPrincipal.from_asn1(ticket_info['sname'],
                                                 ticket_info['srealm'])

        c.time = Times.from_asn1(ticket_info)
        c.key = Keyblock.from_asn1(ticket_info['key'])
        c.is_skey = 0  #not sure!

        c.tktflags = TicketFlags(ticket_info['flags']).cast(
            core.IntegerBitString).native
        c.num_address = 0
        c.num_authdata = 0
        c.ticket = CCACHEOctetString.from_asn1(
            Ticket(krbcred['tickets']
                   [0]).dump())  #kirbi only stores one ticket per file
        c.second_ticket = CCACHEOctetString.empty()

        self.credentials.append(c)
Ejemplo n.º 10
0
    async def authenticate(self,
                           authData,
                           flags=None,
                           seq_number=0,
                           is_rpc=False):
        try:

            if self.kc is None:
                _, err = await self.setup_kc()
                if err is not None:
                    return None, None, err

            if self.iterations == 0:
                try:
                    #check TGS first, maybe ccache already has what we need
                    for target in self.ccred.ccache.list_targets():
                        # just printing this to debug...
                        logger.debug('CCACHE target SPN record: %s' % target)
                    tgs, encpart, self.session_key = await self.kc.get_TGS(
                        self.spn)

                    self.from_ccache = True
                except Exception as e:
                    # this is normal when no credentials stored in ccache
                    #tgt = await self.kc.get_TGT(override_etype=[18])
                    tgt = await self.kc.get_TGT()
                    tgs, encpart, self.session_key = await self.kc.get_TGS(
                        self.spn)

            ap_opts = []
            if is_rpc == True:
                if self.iterations == 0:
                    ap_opts.append('mutual-required')
                    flags = ChecksumFlags.GSS_C_CONF_FLAG | ChecksumFlags.GSS_C_INTEG_FLAG | ChecksumFlags.GSS_C_SEQUENCE_FLAG|\
                      ChecksumFlags.GSS_C_REPLAY_FLAG | ChecksumFlags.GSS_C_MUTUAL_FLAG | ChecksumFlags.GSS_C_DCE_STYLE

                    if self.from_ccache is False:
                        apreq = self.kc.construct_apreq(tgs,
                                                        encpart,
                                                        self.session_key,
                                                        flags=flags,
                                                        seq_number=seq_number,
                                                        ap_opts=ap_opts)
                    else:
                        apreq = self.kc.construct_apreq_from_ticket(
                            Ticket(tgs['ticket']).dump(),
                            self.session_key,
                            tgs['crealm'],
                            tgs['cname']['name-string'][0],
                            flags=flags,
                            seq_number=seq_number,
                            ap_opts=ap_opts,
                            cb_data=None)

                    self.iterations += 1
                    return apreq, False, None

                else:
                    #mutual authentication part here
                    self.seq_number = seq_number

                    aprep = AP_REP.load(authData).native
                    cipher = _enctype_table[int(aprep['enc-part']['etype'])]()
                    cipher_text = aprep['enc-part']['cipher']
                    temp = cipher.decrypt(self.session_key, 12, cipher_text)

                    enc_part = EncAPRepPart.load(temp).native
                    cipher = _enctype_table[int(
                        enc_part['subkey']['keytype'])]()

                    now = datetime.datetime.now(datetime.timezone.utc)
                    apreppart_data = {}
                    apreppart_data['cusec'] = now.microsecond
                    apreppart_data['ctime'] = now.replace(microsecond=0)
                    apreppart_data['seq-number'] = enc_part['seq-number']
                    #print('seq %s' % enc_part['seq-number'])

                    apreppart_data_enc = cipher.encrypt(
                        self.session_key, 12,
                        EncAPRepPart(apreppart_data).dump(), None)

                    #overriding current session key
                    self.session_key = Key(cipher.enctype,
                                           enc_part['subkey']['keyvalue'])

                    ap_rep = {}
                    ap_rep['pvno'] = 5
                    ap_rep['msg-type'] = MESSAGE_TYPE.KRB_AP_REP.value
                    ap_rep['enc-part'] = EncryptedData({
                        'etype':
                        self.session_key.enctype,
                        'cipher':
                        apreppart_data_enc
                    })

                    token = AP_REP(ap_rep).dump()
                    self.gssapi = get_gssapi(self.session_key)
                    self.iterations += 1

                    return token, False, None
            else:
                if self.from_ccache is False:
                    apreq = self.kc.construct_apreq(tgs,
                                                    encpart,
                                                    self.session_key,
                                                    flags=flags,
                                                    seq_number=seq_number,
                                                    ap_opts=ap_opts)
                else:
                    apreq = self.kc.construct_apreq_from_ticket(
                        Ticket(tgs['ticket']).dump(),
                        self.session_key,
                        tgs['crealm'],
                        tgs['cname']['name-string'][0],
                        flags=flags,
                        seq_number=seq_number,
                        ap_opts=ap_opts,
                        cb_data=None)
                return apreq, False, None

        except Exception as e:
            return None, None, e
Ejemplo n.º 11
0
	def S4U2proxy(self, s4uself_ticket, spn_user, supp_enc_methods = [EncryptionType.DES_CBC_CRC,EncryptionType.DES_CBC_MD4,EncryptionType.DES_CBC_MD5,EncryptionType.DES3_CBC_SHA1,EncryptionType.ARCFOUR_HMAC_MD5,EncryptionType.AES256_CTS_HMAC_SHA1_96,EncryptionType.AES128_CTS_HMAC_SHA1_96]):
		logger.debug('[S4U2proxy] Impersonating %s' % '/'.join(spn_user.get_principalname()))
		now = datetime.datetime.now(datetime.timezone.utc)
		supp_enc = self.usercreds.get_preferred_enctype(supp_enc_methods)
		
		pa_pac_opts = {}
		pa_pac_opts['padata-type'] = int(PADATA_TYPE('PA-PAC-OPTIONS'))
		pa_pac_opts['padata-value'] = PA_PAC_OPTIONS({'value' : PA_PAC_OPTIONSTypes(set(['resource-based constrained delegation']))}).dump()

		
		authenticator_data = {}
		authenticator_data['authenticator-vno'] = krb5_pvno
		authenticator_data['crealm'] = Realm(self.kerberos_TGT['crealm'])
		authenticator_data['cname'] = self.kerberos_TGT['cname']
		authenticator_data['cusec'] = now.microsecond
		authenticator_data['ctime'] = now.replace(microsecond=0)
		
		authenticator_data_enc = self.kerberos_cipher.encrypt(self.kerberos_session_key, 7, Authenticator(authenticator_data).dump(), None)
		
		ap_req = {}
		ap_req['pvno'] = krb5_pvno
		ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value
		ap_req['ap-options'] = APOptions(set())
		ap_req['ticket'] = Ticket(self.kerberos_TGT['ticket'])
		ap_req['authenticator'] = EncryptedData({'etype': self.kerberos_cipher_type, 'cipher': authenticator_data_enc})
		
		pa_tgs_req = {}
		pa_tgs_req['padata-type'] = PaDataType.TGS_REQ.value
		pa_tgs_req['padata-value'] = AP_REQ(ap_req).dump()
		
		
		krb_tgs_body = {}
		krb_tgs_body['kdc-options'] = KDCOptions(set(['forwardable','renewable','constrained-delegation', 'canonicalize']))
		krb_tgs_body['sname'] = PrincipalName({'name-type': NAME_TYPE.SRV_INST.value, 'name-string': spn_user.get_principalname()})
		krb_tgs_body['realm'] = self.usercreds.domain.upper()
		krb_tgs_body['till']  = (now + datetime.timedelta(days=1)).replace(microsecond=0)
		krb_tgs_body['nonce'] = secrets.randbits(31)
		krb_tgs_body['etype'] = [supp_enc.value] #selecting according to server's preferences
		krb_tgs_body['additional-tickets'] = [s4uself_ticket]
		
		
		krb_tgs_req = {}
		krb_tgs_req['pvno'] = krb5_pvno
		krb_tgs_req['msg-type'] = MESSAGE_TYPE.KRB_TGS_REQ.value
		krb_tgs_req['padata'] = [pa_tgs_req, pa_pac_opts]
		krb_tgs_req['req-body'] = KDC_REQ_BODY(krb_tgs_body)
		
		req = TGS_REQ(krb_tgs_req)
		logger.debug('[S4U2proxy] Sending request to server')
		try:
			reply = self.ksoc.sendrecv(req.dump())
		except KerberosError as e:
			if e.errorcode.value == 16:
				logger.error('S4U2proxy: Failed to get S4U2proxy! Error code (16) indicates that delegation is not enabled for this account! Full error: %s' % e)
			
			raise e
		logger.debug('[S4U2proxy] Got server reply, decrypting...')
		tgs = reply.native
		
		encTGSRepPart = EncTGSRepPart.load(self.kerberos_cipher.decrypt(self.kerberos_session_key, 8, tgs['enc-part']['cipher'])).native
		key = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue'])
		
		self.ccache.add_tgs(tgs, encTGSRepPart)
		logger.debug('[S4U2proxy] Got valid TGS reply')

		return tgs, encTGSRepPart, key
Ejemplo n.º 12
0
	def S4U2self(self, user_to_impersonate, supp_enc_methods = [EncryptionType.DES_CBC_CRC,EncryptionType.DES_CBC_MD4,EncryptionType.DES_CBC_MD5,EncryptionType.DES3_CBC_SHA1,EncryptionType.ARCFOUR_HMAC_MD5,EncryptionType.AES256_CTS_HMAC_SHA1_96,EncryptionType.AES128_CTS_HMAC_SHA1_96]):
		"""
		user_to_impersonate : KerberosTarget class
		"""
		
		if not self.kerberos_TGT:
			logger.debug('[S4U2self] TGT is not available! Fetching TGT...')
			self.get_TGT()
		
		supp_enc = self.usercreds.get_preferred_enctype(supp_enc_methods)
		auth_package_name = 'Kerberos'
		now = datetime.datetime.now(datetime.timezone.utc)
		
		
		###### Calculating authenticator data
		authenticator_data = {}
		authenticator_data['authenticator-vno'] = krb5_pvno
		authenticator_data['crealm'] = Realm(self.kerberos_TGT['crealm'])
		authenticator_data['cname'] = self.kerberos_TGT['cname']
		authenticator_data['cusec'] = now.microsecond
		authenticator_data['ctime'] = now.replace(microsecond=0)
		
		authenticator_data_enc = self.kerberos_cipher.encrypt(self.kerberos_session_key, 7, Authenticator(authenticator_data).dump(), None)
		
		ap_req = {}
		ap_req['pvno'] = krb5_pvno
		ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value
		ap_req['ap-options'] = APOptions(set())
		ap_req['ticket'] = Ticket(self.kerberos_TGT['ticket'])
		ap_req['authenticator'] = EncryptedData({'etype': self.kerberos_cipher_type, 'cipher': authenticator_data_enc})
		
		pa_data_auth = {}
		pa_data_auth['padata-type'] = PaDataType.TGS_REQ.value
		pa_data_auth['padata-value'] = AP_REQ(ap_req).dump()
		
		###### Calculating checksum data
		
		S4UByteArray = NAME_TYPE.PRINCIPAL.value.to_bytes(4, 'little', signed = False)
		S4UByteArray += user_to_impersonate.username.encode()
		S4UByteArray += user_to_impersonate.domain.encode()
		S4UByteArray += auth_package_name.encode()
		logger.debug('[S4U2self] S4UByteArray: %s' % S4UByteArray.hex())
		logger.debug('[S4U2self] S4UByteArray: %s' % S4UByteArray)
		
		chksum_data = _HMACMD5.checksum(self.kerberos_session_key, 17, S4UByteArray)
		logger.debug('[S4U2self] chksum_data: %s' % chksum_data.hex())
		
		
		chksum = {}
		chksum['cksumtype'] = int(CKSUMTYPE('HMAC_MD5'))
		chksum['checksum'] = chksum_data

		
		###### Filling out PA-FOR-USER data for impersonation
		pa_for_user_enc = {}
		pa_for_user_enc['userName'] = PrincipalName({'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': user_to_impersonate.get_principalname()})
		pa_for_user_enc['userRealm'] = user_to_impersonate.domain
		pa_for_user_enc['cksum'] = Checksum(chksum)
		pa_for_user_enc['auth-package'] = auth_package_name
		
		pa_for_user = {}
		pa_for_user['padata-type'] = int(PADATA_TYPE('PA-FOR-USER'))
		pa_for_user['padata-value'] = PA_FOR_USER_ENC(pa_for_user_enc).dump()
	
		###### Constructing body
		
		krb_tgs_body = {}
		krb_tgs_body['kdc-options'] = KDCOptions(set(['forwardable','renewable','canonicalize']))
		krb_tgs_body['sname'] = PrincipalName({'name-type': NAME_TYPE.UNKNOWN.value, 'name-string': [self.usercreds.username]})
		krb_tgs_body['realm'] = self.usercreds.domain.upper()
		krb_tgs_body['till']  = (now + datetime.timedelta(days=1)).replace(microsecond=0)
		krb_tgs_body['nonce'] = secrets.randbits(31)
		krb_tgs_body['etype'] = [supp_enc.value] #selecting according to server's preferences
		
		
		krb_tgs_req = {}
		krb_tgs_req['pvno'] = krb5_pvno
		krb_tgs_req['msg-type'] = MESSAGE_TYPE.KRB_TGS_REQ.value
		krb_tgs_req['padata'] = [pa_data_auth, pa_for_user]
		krb_tgs_req['req-body'] = KDC_REQ_BODY(krb_tgs_body)
		
		req = TGS_REQ(krb_tgs_req)
		
		logger.debug('[S4U2self] Sending request to server')
		try:
			reply = self.ksoc.sendrecv(req.dump())
		except KerberosError as e:
			if e.errorcode.value == 16:
				logger.error('[S4U2self] Failed to get S4U2self! Error code (16) indicates that delegation is not enabled for this account! Full error: %s' % e)
			
			raise e
		
		logger.debug('[S4U2self] Got reply, decrypting...')
		tgs = reply.native
		
		encTGSRepPart = EncTGSRepPart.load(self.kerberos_cipher.decrypt(self.kerberos_session_key, 8, tgs['enc-part']['cipher'])).native
		key = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue'])
		
		self.ccache.add_tgs(tgs, encTGSRepPart)
		logger.debug('[S4U2self] Got valid TGS reply')
		self.kerberos_TGS = tgs
		return tgs, encTGSRepPart, key
Ejemplo n.º 13
0
	def get_TGS(self, spn_user, override_etype = None, is_linux = False):
		"""
		Requests a TGS ticket for the specified user.
		Returns the TGS ticket, end the decrpyted encTGSRepPart.

		spn_user: KerberosTarget: the service user you want to get TGS for.
		override_etype: None or list of etype values (int) Used mostly for kerberoasting, will override the AP_REQ supported etype values (which is derived from the TGT) to be able to recieve whatever tgs tiecket 
		"""

		logger.debug('[getTGS] Constructing request for user %s' % spn_user.get_formatted_pname())
		now = datetime.datetime.now(datetime.timezone.utc)
		kdc_req_body = {}
		kdc_req_body['kdc-options'] = KDCOptions(set(['forwardable','renewable','renewable_ok', 'canonicalize']))
		kdc_req_body['realm'] = spn_user.domain.upper()
		kdc_req_body['sname'] = PrincipalName({'name-type': NAME_TYPE.SRV_INST.value, 'name-string': spn_user.get_principalname()})
		kdc_req_body['till'] = (now + datetime.timedelta(days=1)).replace(microsecond=0)
		kdc_req_body['nonce'] = secrets.randbits(31)
		if override_etype:
			kdc_req_body['etype'] = override_etype
		else:
			kdc_req_body['etype'] = [self.kerberos_cipher_type]

		authenticator_data = {}
		authenticator_data['authenticator-vno'] = krb5_pvno
		authenticator_data['crealm'] = Realm(self.kerberos_TGT['crealm'])
		authenticator_data['cname'] = self.kerberos_TGT['cname']
		authenticator_data['cusec'] = now.microsecond
		authenticator_data['ctime'] = now.replace(microsecond=0)
		
		if is_linux:
			ac = AuthenticatorChecksum()
			ac.flags = 0
			ac.channel_binding = b'\x00'*16
			
			chksum = {}
			chksum['cksumtype'] = 0x8003
			chksum['checksum'] = ac.to_bytes()
			
			authenticator_data['cksum'] = Checksum(chksum)
			authenticator_data['seq-number'] = 0
		
		authenticator_data_enc = self.kerberos_cipher.encrypt(self.kerberos_session_key, 7, Authenticator(authenticator_data).dump(), None)
		
		ap_req = {}
		ap_req['pvno'] = krb5_pvno
		ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value
		ap_req['ap-options'] = APOptions(set())
		ap_req['ticket'] = Ticket(self.kerberos_TGT['ticket'])
		ap_req['authenticator'] = EncryptedData({'etype': self.kerberos_cipher_type, 'cipher': authenticator_data_enc})
		
		pa_data_1 = {}
		pa_data_1['padata-type'] = PaDataType.TGS_REQ.value
		pa_data_1['padata-value'] = AP_REQ(ap_req).dump()
		
		
		kdc_req = {}
		kdc_req['pvno'] = krb5_pvno
		kdc_req['msg-type'] = MESSAGE_TYPE.KRB_TGS_REQ.value
		kdc_req['padata'] = [pa_data_1]
		kdc_req['req-body'] = KDC_REQ_BODY(kdc_req_body)
		
		req = TGS_REQ(kdc_req)
		logger.debug('[getTGS] Constructing request to server')
		rep = self.ksoc.sendrecv(req.dump())
		logger.debug('[getTGS] Got reply, decrypting...')
		tgs = rep.native
		
		encTGSRepPart = EncTGSRepPart.load(self.kerberos_cipher.decrypt(self.kerberos_session_key, 8, tgs['enc-part']['cipher'])).native
		key = Key(encTGSRepPart['key']['keytype'], encTGSRepPart['key']['keyvalue'])
		
		self.ccache.add_tgs(tgs, encTGSRepPart)
		logger.debug('[getTGS] Got valid reply')
		self.kerberos_TGS = tgs
		return tgs, encTGSRepPart, key
Ejemplo n.º 14
0
    def build_apreq(self,
                    asrep,
                    session_key,
                    cipher,
                    subkey_data,
                    krb_finished_data,
                    flags=GSSAPIFlags.GSS_C_MUTUAL_FLAG
                    | GSSAPIFlags.GSS_C_INTEG_FLAG
                    | GSSAPIFlags.GSS_C_EXTENDED_ERROR_FLAG):

        # TODO: https://www.ietf.org/rfc/rfc4757.txt
        #subkey_data = {}
        #subkey_data['keytype'] = Enctype.AES256
        #subkey_data['keyvalue'] = os.urandom(32)

        subkey_cipher = _enctype_table[subkey_data['keytype']]
        subkey_key = Key(subkey_cipher.enctype, subkey_data['keyvalue'])
        subkey_checksum = _checksum_table[
            16]  # ChecksumTypes.hmac_sha1_96_aes256

        krb_finished_checksum_data = {}
        krb_finished_checksum_data['cksumtype'] = 16
        krb_finished_checksum_data['checksum'] = subkey_checksum.checksum(
            subkey_key, 41, krb_finished_data)

        krb_finished_data = {}
        krb_finished_data['gss-mic'] = Checksum(krb_finished_checksum_data)

        krb_finished = KRB_FINISHED(krb_finished_data).dump()

        a = 2
        extensions_data = a.to_bytes(
            4, byteorder='big', signed=True) + len(krb_finished).to_bytes(
                4, byteorder='big', signed=True) + krb_finished

        ac = AuthenticatorChecksum()
        ac.flags = flags
        ac.channel_binding = b'\x00' * 16
        chksum = {}
        chksum['cksumtype'] = 0x8003
        chksum['checksum'] = ac.to_bytes() + extensions_data

        tii = LSAP_TOKEN_INFO_INTEGRITY()
        tii.Flags = 1
        tii.TokenIL = 0x00002000  # Medium integrity
        tii.MachineID = bytes.fromhex(
            '7e303fffe6bff25146addca4fbddf1b94f1634178eb4528fb2731c669ca23cde')

        restriction_data = {}
        restriction_data['restriction-type'] = 0
        restriction_data['restriction'] = tii.to_bytes()
        restriction_data = KERB_AD_RESTRICTION_ENTRY(restriction_data)

        x = KERB_AD_RESTRICTION_ENTRYS([restriction_data]).dump()
        restrictions = AuthorizationData([{
            'ad-type': 141,
            'ad-data': x
        }]).dump()

        now = datetime.datetime.now(datetime.timezone.utc)
        authenticator_data = {}
        authenticator_data['authenticator-vno'] = krb5_pvno
        authenticator_data['crealm'] = Realm(asrep['crealm'])
        authenticator_data['cname'] = asrep['cname']
        authenticator_data['cusec'] = now.microsecond
        authenticator_data['ctime'] = now.replace(microsecond=0)
        authenticator_data['subkey'] = EncryptionKey(subkey_data)
        authenticator_data['seq-number'] = 682437742  #??? TODO: check this!
        authenticator_data['authorization-data'] = AuthorizationData([{
            'ad-type':
            1,
            'ad-data':
            restrictions
        }])
        authenticator_data['cksum'] = Checksum(chksum)

        #print('Authenticator(authenticator_data).dump()')
        #print(Authenticator(authenticator_data).dump().hex())

        authenticator_data_enc = cipher.encrypt(
            session_key, 11,
            Authenticator(authenticator_data).dump(), None)

        ap_opts = ['mutual-required']

        ap_req = {}
        ap_req['pvno'] = krb5_pvno
        ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value
        ap_req['ticket'] = Ticket(asrep['ticket'])
        ap_req['ap-options'] = APOptions(set(ap_opts))
        ap_req['authenticator'] = EncryptedData({
            'etype':
            session_key.enctype,
            'cipher':
            authenticator_data_enc
        })

        #pprint('AP_REQ \r\n%s' % AP_REQ(ap_req).native)

        #print(AP_REQ(ap_req).dump().hex())
        #input()

        return AP_REQ(ap_req).dump()
Ejemplo n.º 15
0
    async def S4U2proxy(
        self,
        s4uself_ticket,
        spn_user,
        supp_enc_methods=[
            EncryptionType.DES_CBC_CRC, EncryptionType.DES_CBC_MD4,
            EncryptionType.DES_CBC_MD5, EncryptionType.DES3_CBC_SHA1,
            EncryptionType.ARCFOUR_HMAC_MD5,
            EncryptionType.AES256_CTS_HMAC_SHA1_96,
            EncryptionType.AES128_CTS_HMAC_SHA1_96
        ]):
        now = datetime.datetime.now(datetime.timezone.utc)
        supp_enc = self.usercreds.get_preferred_enctype(supp_enc_methods)

        pa_pac_opts = {}
        pa_pac_opts['padata-type'] = int(PADATA_TYPE('PA-PAC-OPTIONS'))
        pa_pac_opts['padata-value'] = PA_PAC_OPTIONS({
            'value':
            PA_PAC_OPTIONSTypes(set(['resource-based constrained delegation']))
        }).dump()

        authenticator_data = {}
        authenticator_data['authenticator-vno'] = krb5_pvno
        authenticator_data['crealm'] = Realm(self.kerberos_TGT['crealm'])
        authenticator_data['cname'] = self.kerberos_TGT['cname']
        authenticator_data['cusec'] = now.microsecond
        authenticator_data['ctime'] = now.replace(microsecond=0)

        authenticator_data_enc = self.kerberos_cipher.encrypt(
            self.kerberos_session_key, 7,
            Authenticator(authenticator_data).dump(), None)

        ap_req = {}
        ap_req['pvno'] = krb5_pvno
        ap_req['msg-type'] = MESSAGE_TYPE.KRB_AP_REQ.value
        ap_req['ap-options'] = APOptions(set())
        ap_req['ticket'] = Ticket(self.kerberos_TGT['ticket'])
        ap_req['authenticator'] = EncryptedData({
            'etype':
            self.kerberos_cipher_type,
            'cipher':
            authenticator_data_enc
        })

        pa_tgs_req = {}
        pa_tgs_req['padata-type'] = PaDataType.TGS_REQ.value
        pa_tgs_req['padata-value'] = AP_REQ(ap_req).dump()

        krb_tgs_body = {}
        #krb_tgs_body['kdc-options'] = KDCOptions(set(['forwardable','forwarded','renewable','renewable-ok', 'canonicalize']))
        krb_tgs_body['kdc-options'] = KDCOptions(
            set([
                'forwardable', 'renewable', 'constrained-delegation',
                'canonicalize'
            ]))
        krb_tgs_body['sname'] = PrincipalName({
            'name-type':
            NAME_TYPE.SRV_INST.value,
            'name-string':
            spn_user.get_principalname()
        })
        krb_tgs_body['realm'] = self.usercreds.domain.upper()
        krb_tgs_body['till'] = (now + datetime.timedelta(days=1)).replace(
            microsecond=0)
        krb_tgs_body['nonce'] = secrets.randbits(31)
        krb_tgs_body['etype'] = [
            supp_enc.value
        ]  #selecting according to server's preferences
        krb_tgs_body['additional-tickets'] = [s4uself_ticket]

        krb_tgs_req = {}
        krb_tgs_req['pvno'] = krb5_pvno
        krb_tgs_req['msg-type'] = MESSAGE_TYPE.KRB_TGS_REQ.value
        krb_tgs_req['padata'] = [pa_tgs_req, pa_pac_opts]
        krb_tgs_req['req-body'] = KDC_REQ_BODY(krb_tgs_body)

        req = TGS_REQ(krb_tgs_req)

        reply = await self.ksoc.sendrecv(req.dump())
        if reply.name == 'KRB_ERROR':
            if reply.native['error-code'] == 16:
                logger.error(
                    'S4U2proxy: Failed to get S4U2proxy! Error code (16) indicates that delegation is not enabled for this account!'
                )

            raise Exception('S4U2proxy failed! %s' % str(reply))
Ejemplo n.º 16
0
    async def authenticate(self,
                           authData,
                           flags=None,
                           seq_number=0,
                           cb_data=None):
        """
		This function is called (multiple times depending on the flags) to perform authentication. 
		"""
        try:
            if self.kc is None:
                _, err = await self.setup_kc()
                if err is not None:
                    return None, None, err

            if self.iterations == 0:
                self.seq_number = 0
                self.iterations += 1

                try:
                    #check TGS first, maybe ccache already has what we need
                    for target in self.ccred.ccache.list_targets():
                        # just printing this to debug...
                        logger.debug('CCACHE SPN record: %s' % target)
                    tgs, encpart, self.session_key = await self.kc.get_TGS(
                        self.spn)

                    self.from_ccache = True
                except:
                    tgt = await self.kc.get_TGT(
                        override_etype=self.preferred_etypes)
                    tgs, encpart, self.session_key = await self.kc.get_TGS(
                        self.spn)  #, override_etype = self.preferred_etypes)

                #self.expected_server_seq_number = encpart.get('nonce', seq_number)

                ap_opts = []
                if ChecksumFlags.GSS_C_MUTUAL_FLAG in self.flags or ChecksumFlags.GSS_C_DCE_STYLE in self.flags:
                    if ChecksumFlags.GSS_C_MUTUAL_FLAG in self.flags:
                        ap_opts.append('mutual-required')
                    if self.from_ccache is False:
                        apreq = self.kc.construct_apreq(
                            tgs,
                            encpart,
                            self.session_key,
                            flags=self.flags,
                            seq_number=self.seq_number,
                            ap_opts=ap_opts,
                            cb_data=cb_data)
                    else:
                        apreq = self.kc.construct_apreq_from_ticket(
                            Ticket(tgs['ticket']).dump(),
                            self.session_key,
                            tgs['crealm'],
                            tgs['cname']['name-string'][0],
                            flags=self.flags,
                            seq_number=self.seq_number,
                            ap_opts=ap_opts,
                            cb_data=cb_data)
                    return apreq, True, None

                else:
                    #no mutual or dce auth will take one step only
                    if self.from_ccache is False:
                        apreq = self.kc.construct_apreq(
                            tgs,
                            encpart,
                            self.session_key,
                            flags=self.flags,
                            seq_number=self.seq_number,
                            ap_opts=[],
                            cb_data=cb_data)
                    else:
                        apreq = self.kc.construct_apreq_from_ticket(
                            Ticket(tgs['ticket']).dump(),
                            self.session_key,
                            tgs['crealm'],
                            tgs['cname']['name-string'][0],
                            flags=self.flags,
                            seq_number=self.seq_number,
                            ap_opts=ap_opts,
                            cb_data=cb_data)

                    self.gssapi = get_gssapi(self.session_key)
                    return apreq, False, None

            else:
                self.iterations += 1
                if ChecksumFlags.GSS_C_DCE_STYLE in self.flags:
                    # adata = authData[16:]
                    # if ChecksumFlags.GSS_C_DCE_STYLE in self.flags:
                    #	adata = authData
                    raise Exception('DCE auth Not implemented!')

                # at this point we are dealing with mutual authentication
                # This means that the server sent back an AP-rep wrapped in a token
                # The APREP contains a new session key we'd need to update and a seq-number
                # that is expected the server will use for future communication.
                # For mutual auth we dont need to reply anything after this step,
                # but for DCE auth a reply is expected. TODO

                # converting the token to aprep
                token = KRB5_MECH_INDEP_TOKEN.from_bytes(authData)
                if token.data[:2] != b'\x02\x00':
                    raise Exception('Unexpected token type! %s' %
                                    token.data[:2].hex())
                aprep = AP_REP.load(token.data[2:]).native

                # decrypting aprep
                cipher = _enctype_table[int(aprep['enc-part']['etype'])]()
                cipher_text = aprep['enc-part']['cipher']
                temp = cipher.decrypt(self.session_key, 12, cipher_text)
                enc_part = EncAPRepPart.load(temp).native

                #updating session key, gssapi
                self.session_key = Key(int(enc_part['subkey']['keytype']),
                                       enc_part['subkey']['keyvalue'])
                #self.seq_number = enc_part.get('seq-number', 0)
                self.gssapi = get_gssapi(self.session_key)

                return b'', False, None

        except Exception as e:
            return None, None, e