Example #1
0
	def build_asreq_lts(self, supported_encryption_method, kdcopts = ['forwardable','renewable','proxiable']):
		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()
		
		
		logger.debug('Selecting common encryption type: %s' % supported_encryption_method.name)
		self.kerberos_cipher = _enctype_table[supported_encryption_method.value]
		self.kerberos_cipher_type = supported_encryption_method.value
		self.kerberos_key = Key(self.kerberos_cipher.enctype, self.usercreds.get_key_for_enctype(supported_encryption_method, 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': supported_encryption_method.value, 'cipher': enc_timestamp}).dump()
		
		kdc_req_body = {}
		kdc_req_body['kdc-options'] = KDCOptions(set(kdcopts))
		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'] = [supported_encryption_method.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)
		
		return AS_REQ(kdc_req)
Example #2
0
    def construct_tgt_req(self):
        now = 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.spn.username]
        })
        kdc_req_body['realm'] = self.spn.domain.upper()
        kdc_req_body['sname'] = PrincipalName({
            'name-type':
            NAME_TYPE.PRINCIPAL.value,
            'name-string': ['krbtgt', self.spn.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'] = [2, 3, 16, 23, 17,
                                 18]  #we "support" all MS related enctypes

        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)

        return AS_REQ(kdc_req)
Example #3
0
	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]

		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')
		return self.ksoc.sendrecv(req.dump())
Example #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 
Example #5
0
    def build_asreq_pkinit(
            self,
            supported_encryption_method,
            kdcopts=['forwardable', 'renewable', 'renewable-ok']):
        from asn1crypto import keys

        if supported_encryption_method.value == 23:
            raise Exception(
                'RC4 encryption is not supported for certificate auth!')

        now = datetime.datetime.now(datetime.timezone.utc)

        kdc_req_body_data = {}
        kdc_req_body_data['kdc-options'] = KDCOptions(set(kdcopts))
        kdc_req_body_data['cname'] = PrincipalName({
            'name-type':
            NAME_TYPE.PRINCIPAL.value,
            'name-string': [self.usercreds.username]
        })
        kdc_req_body_data['realm'] = self.usercreds.domain.upper()
        kdc_req_body_data['sname'] = PrincipalName({
            'name-type':
            NAME_TYPE.SRV_INST.value,
            'name-string': ['krbtgt', self.usercreds.domain.upper()]
        })
        kdc_req_body_data['till'] = (now + datetime.timedelta(days=1)).replace(
            microsecond=0)
        kdc_req_body_data['rtime'] = (now +
                                      datetime.timedelta(days=1)).replace(
                                          microsecond=0)
        kdc_req_body_data['nonce'] = secrets.randbits(31)
        kdc_req_body_data['etype'] = [supported_encryption_method.value
                                      ]  #[18,17] # 23 breaks...
        kdc_req_body = KDC_REQ_BODY(kdc_req_body_data)

        checksum = hashlib.sha1(kdc_req_body.dump()).digest()

        authenticator = {}
        authenticator['cusec'] = now.microsecond
        authenticator['ctime'] = now.replace(microsecond=0)
        authenticator['nonce'] = secrets.randbits(31)
        authenticator['paChecksum'] = checksum

        dp = {}
        dp['p'] = self.usercreds.dhparams.p
        dp['g'] = self.usercreds.dhparams.g
        dp['q'] = 0  # mandatory parameter, but it is not needed

        pka = {}
        pka['algorithm'] = '1.2.840.10046.2.1'
        pka['parameters'] = keys.DomainParameters(dp)

        spki = {}
        spki['algorithm'] = keys.PublicKeyAlgorithm(pka)
        spki['public_key'] = self.usercreds.dhparams.get_public_key()

        authpack = {}
        authpack['pkAuthenticator'] = PKAuthenticator(authenticator)
        authpack['clientPublicValue'] = keys.PublicKeyInfo(spki)
        authpack['clientDHNonce'] = self.usercreds.dhparams.dh_nonce

        authpack = AuthPack(authpack)
        signed_authpack = self.usercreds.sign_authpack(authpack.dump(),
                                                       wrap_signed=True)

        payload = PA_PK_AS_REQ()
        payload['signedAuthPack'] = signed_authpack

        pa_data_1 = {}
        pa_data_1['padata-type'] = PaDataType.PK_AS_REQ.value
        pa_data_1['padata-value'] = payload.dump()

        pa_data_0 = {}
        pa_data_0['padata-type'] = int(PADATA_TYPE('PA-PAC-REQUEST'))
        pa_data_0['padata-value'] = PA_PAC_REQUEST({
            'include-pac': True
        }).dump()

        asreq = {}
        asreq['pvno'] = 5
        asreq['msg-type'] = 10
        asreq['padata'] = [pa_data_0, pa_data_1]
        asreq['req-body'] = kdc_req_body

        return AS_REQ(asreq)