diff --git a/minikerberos/aioclient.py b/minikerberos/aioclient.py index 4f846b5..8dca618 100644 --- a/minikerberos/aioclient.py +++ b/minikerberos/aioclient.py @@ -845,9 +845,21 @@ async def get_referral_ticket(self, target_domain, target_ip = None): tgs, encpart, key = await self.get_TGS(crossrealm_spn) logger.debug('Got referral ticket!') + for _ in range(10): # 10 is arbitrary, but I fail to imagine a scenario where we would need more than 10 referrals + if encpart['sname']['name-string'][1].upper() == target_domain.upper(): + break - kirbi = Kirbi.from_ticketdata(tgs, encpart) + # otherwise we have to do this again with the new krbtgt + logger.debug('The referral ticket is not for the target domain, getting new referral ticket from %s' % encpart['sname']['name-string'][1]) + + kirbi = Kirbi.from_ticketdata(tgs, encpart) + newt = self.target.get_newtarget(encpart['sname']['name-string'][1], port=88) + newc = KerberosCredential.from_kirbi(kirbi, encoding='kirbi') + new_factory = KerberosClientFactory(newt, newc, newt.proxies) + newclient = new_factory.get_client() + tgs, encpart, key, new_factory = await newclient.get_referral_ticket(target_domain, target_ip) + kirbi = Kirbi.from_ticketdata(tgs, encpart) target_addr = target_domain if target_ip is not None: target_addr = target_ip diff --git a/minikerberos/common/spn.py b/minikerberos/common/spn.py index 26e2687..0e9aa99 100644 --- a/minikerberos/common/spn.py +++ b/minikerberos/common/spn.py @@ -5,6 +5,7 @@ def __init__(self): self.username = None self.service = None #the service we are trying to get a ticket for (eg. cifs/mssql...) self.domain = None #the kerberos realm + self.port = None #the port the service is running on # https://docs.microsoft.com/en-us/windows/desktop/ad/name-formats-for-unique-spns #def from_spn(self): @@ -45,16 +46,23 @@ def from_spn(s, override_realm:str = None): raise Exception('The following SPN is incorrect without additionally setting the realm: %s' % s) if override_realm is not None: kt.domain = override_realm + if kt.domain.find(':') != -1: + kt.domain, kt.port = kt.domain.split(':', 1) return kt def get_principalname(self): if self.service: + if self.port: + return [self.service, '%s:%s' % (self.username, self.port)] return [self.service, self.username] return [self.username] def get_formatted_pname(self): if self.service: - return '%s/%s@%s' % (self.service, self.username, self.domain) + if self.port: + return '%s/%s:%s@%s' % (self.service, self.username, self.port, self.domain) + else: + return '%s/%s@%s' % (self.service, self.username, self.domain) return '%s@%s' % (self.username, self.domain) def __str__(self):