Пример #1
0
    def sendrecv(self, data, throw=True):
        #throw variable indicates wether to create an exception when a kerberos error happens or just return the kerberos error"
        #for any other exceptions types (eg. connection related errors) an exception will be raised regardless

        self.create_soc()
        try:
            if self.soc_type == KerberosSocketType.TCP:
                length = len(data).to_bytes(4, byteorder='big', signed=False)
                self.soc.sendall(length + data)
                buff = b''
                total_length = -1
                while True:
                    temp = b''
                    temp = self.soc.recv(4096)
                    if temp == b'':
                        break
                    buff += temp
                    if total_length == -1:
                        if len(buff) > 4:
                            total_length = int.from_bytes(buff[:4],
                                                          byteorder='big',
                                                          signed=False)
                            if total_length == 0:
                                raise Exception(
                                    'Returned data length is 0! This means the server did not understand our message'
                                )

                    if total_length != -1:
                        if len(buff) == total_length + 4:
                            buff = buff[4:]
                            break
                        elif len(buff) > total_length + 4:
                            raise Exception('Got too much data somehow')
                        else:
                            continue

            elif self.soc_type == KerberosSocketType.UDP:
                self.soc.sendto(data, (self.dst_ip, self.dst_port))
                while True:
                    buff, addr = self.soc.recvfrom(65535)
                    if addr[0] == self.dst_ip:
                        break
                    else:
                        # got a message from a different IP than the target, strange!
                        # continuing, but this might result in an infinite loop
                        continue
            if buff == b'':
                raise Exception('Server closed the connection!')
            krb_message = KerberosResponse.load(buff)
            if krb_message.name == 'KRB_ERROR' and throw == True:
                raise KerberosError(krb_message)
            return krb_message
        finally:
            self.soc.close()
Пример #2
0
	def do_preauth(self, supported_encryption_method, kdcopts = ['forwardable','renewable','renewable-ok']):
		if self.usercreds.certificate is not None:
			req = self.build_asreq_pkinit(supported_encryption_method, kdcopts)
		else:
			req = self.build_asreq_lts(supported_encryption_method, kdcopts)

		
		logger.debug('Sending TGT request to server')
		rep = self.ksoc.sendrecv(req.dump())
		if rep.name == 'KRB_ERROR':
			raise KerberosError(rep, 'Preauth failed!')
		return rep
Пример #3
0
def decrypt_pk_dh(data, diffieHellmanExchange):
    try:
        rep = SPNEGO_PKINIT_AS_REP.load(bytes.fromhex(data)).native
    except:
        krb_message = KerberosResponse.load(bytes.fromhex(data))
        raise KerberosError(krb_message)

    relevantPadata = None
    for padata in rep['Kerberos']['padata']:
        if padata['padata-type'] == 17:
            relevantPadata = PA_PK_AS_REP.load(padata['padata-value']).native
            break

    if not relevantPadata:
        raise Exception('No PAdata found with type 17')
    keyinfo = SignedData.load(
        relevantPadata['dhSignedData']).native['encap_content_info']
    if keyinfo['content_type'] != '1.3.6.1.5.2.3.2':
        raise Exception('Keyinfo content type unexpected value')
    authdata = KDCDHKeyInfo.load(keyinfo['content']).native
    pubkey = int(
        ''.join(['1'] + [str(x) for x in authdata['subjectPublicKey']]), 2)

    pubkey = int.from_bytes(core.BitString(
        authdata['subjectPublicKey']).dump()[7:],
                            'big',
                            signed=False)
    shared_key = diffieHellmanExchange.exchange(pubkey)

    server_nonce = relevantPadata['serverDHNonce']
    fullKey = shared_key + diffieHellmanExchange.dh_nonce + server_nonce

    etype = rep['Kerberos']['enc-part']['etype']
    cipher = _enctype_table[etype]
    if etype == Enctype.AES256:
        t_key = truncate(fullKey, 32)
    elif etype == Enctype.AES128:
        t_key = truncate(fullKey, 16)
    elif etype == Enctype.RC4:
        raise NotImplementedError(
            'RC4 key truncation documentation missing. it is different from AES'
        )

    key = Key(cipher.enctype, t_key)
    enc_data = rep['Kerberos']['enc-part']['cipher']
    dec_data = cipher.decrypt(key, 3, enc_data)
    encasrep = EncASRepPart.load(dec_data).native
    cipher = _enctype_table[int(encasrep['key']['keytype'])]
    session_key = Key(cipher.enctype, encasrep['key']['keyvalue'])

    return session_key, cipher, rep

    # remove Octet String manualy
    padata = str(rep['padata'][0]['padata-value']).encode('hex')
    parsedPadata = decode(padata.decode('hex'), asn1Spec=AS_REP_Padata())[0]
    decoded = parsedPadata['DHRepInfo']['dhSignedData']
    kdcSignedDataResponse = decode(decoded, asn1Spec=SignedData())[0]
    kdcDHKeyInfo = str(kdcSignedDataResponse['encapContentInfo']
                       ['id-pkinit-authData-value']).encode('hex')
    d = decode(kdcDHKeyInfo.decode('hex'), asn1Spec=KDCDHKeyInfo())[0]
    dcPublicKey = int(encode(d['subjectPublicKey']).encode('hex')[20:], 16)

    dcPublicNumbers = dh.DHPublicNumbers(dcPublicKey, diffieHellmanExchange[2])

    backend = default_backend()

    dcPublicKey = backend.load_dh_public_numbers(dcPublicNumbers)
    shared_key = diffieHellmanExchange[1].exchange(dcPublicKey)
    sharedHexKey = shared_key.encode('hex')

    clientDHNonce = '6B328FA66EEBDFD3D69ED34E5007776AB30832A2ED1DCB1699781BFE0BEDF87A'
    serverDHNonce = encode(
        parsedPadata['DHRepInfo']['encKeyPack']).encode('hex')[8:]

    fullKey = sharedHexKey + clientDHNonce + serverDHNonce

    etype = rep['enc-part']['etype']
    cipher = _enctype_table[etype]
    if etype == Enctype.AES256:
        truncateKey = truncate(fullKey, 32)
        key = Key(cipher.enctype, truncateKey)

    elif etype == Enctype.AES128:
        truncateKey = truncate(fullKey, 16)
        key = Key(cipher.enctype, truncateKey)

    elif etype == Enctype.RC4:
        truncateKey = truncate(fullKey, 16)
        key = Key(cipher.enctype, truncateKey)

    cipherText = rep['enc-part']['cipher'].asOctets()
    plainText = cipher.decrypt(key, 3, cipherText)
    encASRepPart = decode(plainText, asn1Spec=EncASRepPart())[0]
    cipher = _enctype_table[int(encASRepPart['key']['keytype'])]
    session_key = Key(cipher.enctype,
                      encASRepPart['key']['keyvalue'].asOctets())
    return session_key, cipher, rep
Пример #4
0
	def get_TGT(self, override_etype = None, decrypt_tgt = True):
		"""
		decrypt_tgt: used for asreproast attacks
		Steps performed:
			1. Send and empty (no encrypted timestamp) AS_REQ with all the encryption types we support
			2. Depending on the response (either error or AS_REP with TGT) we either send another AS_REQ with the encrypted data or return the TGT (or fail miserably)
			3. PROFIT
		"""
		logger.debug('[getTGT] Generating initial TGT without authentication data')
		now = datetime.datetime.now(datetime.timezone.utc)
		kdc_req_body = {}
		kdc_req_body['kdc-options'] = KDCOptions(set(['forwardable','renewable','proxiable']))
		kdc_req_body['cname'] = PrincipalName({'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': [self.usercreds.username]})
		kdc_req_body['realm'] = self.usercreds.domain.upper()
		kdc_req_body['sname'] = PrincipalName({'name-type': NAME_TYPE.PRINCIPAL.value, 'name-string': ['krbtgt', self.usercreds.domain.upper()]})
		kdc_req_body['till']  = (now + datetime.timedelta(days=1)).replace(microsecond=0)
		kdc_req_body['rtime'] = (now + datetime.timedelta(days=1)).replace(microsecond=0)
		kdc_req_body['nonce'] = secrets.randbits(31)
		if override_etype is None:
			kdc_req_body['etype'] = self.usercreds.get_supported_enctypes()
		else:
			kdc_req_body['etype'] = override_etype

		pa_data_1 = {}
		pa_data_1['padata-type'] = int(PADATA_TYPE('PA-PAC-REQUEST'))
		pa_data_1['padata-value'] = PA_PAC_REQUEST({'include-pac': True}).dump()
		
		kdc_req = {}
		kdc_req['pvno'] = krb5_pvno
		kdc_req['msg-type'] = MESSAGE_TYPE.KRB_AS_REQ.value
		kdc_req['padata'] = [pa_data_1]
		kdc_req['req-body'] = KDC_REQ_BODY(kdc_req_body)

		req = AS_REQ(kdc_req)	
		
		logger.debug('[getTGT] Sending initial TGT to %s' % self.ksoc.get_addr_str())
		rep = self.ksoc.sendrecv(req.dump(), throw = False)

		if rep.name != 'KRB_ERROR':
			#user can do kerberos auth without preauthentication!
			self.kerberos_TGT = rep.native

			etype = self.kerberos_TGT['enc-part']['etype']

			#if we want to roast the asrep (tgt rep) part then we dont even have the proper keys to decrypt
			#so we just return, the asrep can be extracted from this object anyhow
			if decrypt_tgt == False:
				return

			self.kerberos_cipher = _enctype_table[etype]
			self.kerberos_cipher_type = etype
			encryption_type = EncryptionType(self.kerberos_cipher.enctype)
			enctype = self.usercreds.get_key_for_enctype(encryption_type)
			self.kerberos_key = Key(self.kerberos_cipher.enctype, enctype)
			
		else:
			if rep.native['error-code'] != KerberosErrorCode.KDC_ERR_PREAUTH_REQUIRED.value:
				raise KerberosError(rep)
			rep = rep.native
			logger.debug('[getTGT] Got reply from server, asking to provide auth data')
			
			rep = self.do_preauth(rep)
			logger.debug('[getTGT] Got valid response from server')
			rep = rep.native
			self.kerberos_TGT = rep

		cipherText = self.kerberos_TGT['enc-part']['cipher']
		temp = self.kerberos_cipher.decrypt(self.kerberos_key, 3, cipherText)
		try:
			self.kerberos_TGT_encpart = EncASRepPart.load(temp).native
		except Exception as e:
			logger.debug('[getTGT] EncAsRepPart load failed, is this linux?')
			try:
				self.kerberos_TGT_encpart = EncTGSRepPart.load(temp).native
			except Exception as e:
				logger.error('[getTGT] Failed to load decrypted part of the reply!')
				raise e
				
		self.kerberos_session_key = Key(self.kerberos_cipher.enctype, self.kerberos_TGT_encpart['key']['keyvalue'])
		self.ccache.add_tgt(self.kerberos_TGT, self.kerberos_TGT_encpart, override_pp = True)
		logger.debug('[getTGT] Got valid TGT')
		
		return 
Пример #5
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
        ]):
        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','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':
            emsg = 'S4U2proxy failed!'
            if reply.native['error-code'] == 16:
                emsg = 'S4U2proxy: Failed to get S4U2proxy! Error code (16) indicates that delegation is not enabled for this account!'

            raise KerberosError(reply, emsg)

        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
Пример #6
0
    async def S4U2self(
        self,
        user_to_impersonate,
        spn_user=None,
        kdcopts=['forwardable', 'renewable', 'canonicalize'],
        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
        spn_user = [self.usercreds.username]
        if spn_user is not None:
            if isinstance(spn_user, str):
                spn_user = [spn_user]
            elif isinstance(spn_user, list):
                spn_user = spn_user
            else:
                spn_user = spn_user.get_principalname()

        krb_tgs_body = {}
        krb_tgs_body['kdc-options'] = KDCOptions(set(kdcopts))
        krb_tgs_body['sname'] = PrincipalName({
            'name-type': NAME_TYPE.UNKNOWN.value,
            'name-string': spn_user
        })
        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')

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

        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
Пример #7
0
    async def get_TGS(self, spn_user, override_etype=None, is_linux=False):
        """
		Requests a TGS ticket for the specified user.
		Retruns 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 
		"""

        #first, let's check if CCACHE has the correct ticket already
        tgs, encTGSRepPart, key, err = self.tgs_from_ccache(
            spn_user, override_etype)
        if err is None:
            return tgs, encTGSRepPart, key

        if self.kerberos_TGT is None:
            #let's check if CCACHE has a TGT for us
            _, err = self.tgt_from_ccache(override_etype=override_etype)
            if err is not None:
                raise Exception('No TGT found in CCACHE!')

        #nope, we need to contact the server
        logger.debug('Constructing TGS 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('Constructing TGS request to server')
        rep = await self.ksoc.sendrecv(req.dump())
        if rep.name == 'KRB_ERROR':
            raise KerberosError(rep, 'get_TGS failed!')
        logger.debug('Got TGS 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('Got valid TGS reply')
        self.kerberos_TGS = tgs
        return tgs, encTGSRepPart, key
Пример #8
0
    async def do_preauth(self, rep):
        #now getting server's supported encryption methods

        supp_enc_methods = collections.OrderedDict()
        for enc_method in METHOD_DATA.load(rep['e-data']).native:
            data_type = PaDataType(enc_method['padata-type'])

            if data_type == PaDataType.ETYPE_INFO or data_type == PaDataType.ETYPE_INFO2:
                if data_type == PaDataType.ETYPE_INFO:
                    enc_info_list = ETYPE_INFO.load(enc_method['padata-value'])

                elif data_type == PaDataType.ETYPE_INFO2:
                    enc_info_list = ETYPE_INFO2.load(
                        enc_method['padata-value'])

                for enc_info in enc_info_list.native:
                    supp_enc_methods[EncryptionType(
                        enc_info['etype'])] = enc_info['salt']
                    logger.debug(
                        'Server supports encryption type %s with salt %s' %
                        (EncryptionType(
                            enc_info['etype']).name, enc_info['salt']))

        logger.debug('Constructing TGT request with auth data')
        #now to create an AS_REQ with encrypted timestamp for authentication
        pa_data_1 = {}
        pa_data_1['padata-type'] = int(PADATA_TYPE('PA-PAC-REQUEST'))
        pa_data_1['padata-value'] = PA_PAC_REQUEST({
            'include-pac': True
        }).dump()

        now = datetime.datetime.now(datetime.timezone.utc)
        #creating timestamp asn1
        timestamp = PA_ENC_TS_ENC({
            'patimestamp': now.replace(microsecond=0),
            'pausec': now.microsecond
        }).dump()

        supp_enc = self.usercreds.get_preferred_enctype(supp_enc_methods)
        logger.debug('Selecting common encryption type: %s' % supp_enc.name)
        self.kerberos_cipher = _enctype_table[supp_enc.value]
        self.kerberos_cipher_type = supp_enc.value
        if 'salt' in enc_info and enc_info['salt'] is not None:
            self.server_salt = enc_info['salt'].encode()
        self.kerberos_key = Key(
            self.kerberos_cipher.enctype,
            self.usercreds.get_key_for_enctype(supp_enc,
                                               salt=self.server_salt))
        enc_timestamp = self.kerberos_cipher.encrypt(self.kerberos_key, 1,
                                                     timestamp, None)

        pa_data_2 = {}
        pa_data_2['padata-type'] = int(PADATA_TYPE('ENC-TIMESTAMP'))
        pa_data_2['padata-value'] = EncryptedData({
            'etype': supp_enc.value,
            'cipher': enc_timestamp
        }).dump()

        kdc_req_body = {}
        kdc_req_body['kdc-options'] = KDCOptions(
            set(['forwardable', 'renewable', 'proxiable']))
        kdc_req_body['cname'] = PrincipalName({
            'name-type':
            NAME_TYPE.PRINCIPAL.value,
            'name-string': [self.usercreds.username]
        })
        kdc_req_body['realm'] = self.usercreds.domain.upper()
        kdc_req_body['sname'] = PrincipalName({
            'name-type':
            NAME_TYPE.PRINCIPAL.value,
            'name-string': ['krbtgt', self.usercreds.domain.upper()]
        })
        kdc_req_body['till'] = (now + datetime.timedelta(days=1)).replace(
            microsecond=0)
        kdc_req_body['rtime'] = (now + datetime.timedelta(days=1)).replace(
            microsecond=0)
        kdc_req_body['nonce'] = secrets.randbits(31)
        kdc_req_body['etype'] = [
            supp_enc.value
        ]  #selecting according to server's preferences

        kdc_req = {}
        kdc_req['pvno'] = krb5_pvno
        kdc_req['msg-type'] = MESSAGE_TYPE.KRB_AS_REQ.value
        kdc_req['padata'] = [pa_data_2, pa_data_1]
        kdc_req['req-body'] = KDC_REQ_BODY(kdc_req_body)

        req = AS_REQ(kdc_req)

        logger.debug('Sending TGT request to server')
        rep = await self.ksoc.sendrecv(req.dump())
        if rep.name == 'KRB_ERROR':
            raise KerberosError(rep, 'Preauth failed!')
        return rep