async def __executor(self, tid, target): try: for protocol in self.protocols: smb_mgr = SMBConnectionURL( 'smb2+ntlm-password://%s/?timeout=%s' % (target, self.timeout)) connection = smb_mgr.create_connection_newtarget(target) res, sign_en, sign_req, rply, err = await connection.protocol_test( [protocol]) if err is not None: raise err er = SMBProtocolEnumResultInner( tid, target, (protocol, res, sign_en, sign_req, rply, err)) await self.res_q.put(er) if self.only_signing is True: return except asyncio.CancelledError: return except Exception as e: await self.res_q.put( SMBProtocolEnumResultInner(tid, target, None, error=e, status=EnumResultStatus.ERROR)) finally: await self.res_q.put( SMBProtocolEnumResultInner(tid, target, None, status=EnumResultStatus.FINISHED))
async def __executor(self, tid, target): try: smb_mgr = SMBConnectionURL('smb2+ntlm-password://%s/?timeout=%s' % (target, self.timeout)) connection = smb_mgr.create_connection_newtarget(target) res, err = await connection.fake_login() if err is not None: raise err er = EnumResult(tid, target, (res, )) await self.res_q.put(er) except asyncio.CancelledError: return except Exception as e: await self.res_q.put( EnumResult(tid, target, None, error=e, status=EnumResultStatus.ERROR)) finally: await self.res_q.put( EnumResult(tid, target, None, status=EnumResultStatus.FINISHED))
class SMBAdminCheck: def __init__(self, smb_url, worker_count = 100, enum_url = True): self.target_gens = [] self.smb_mgr = SMBConnectionURL(smb_url) self.worker_count = worker_count self.task_q = None self.res_q = None self.workers = [] self.result_processing_task = None self.enum_url = enum_url self.__gens_finished = False self.__total_targets = 0 self.__total_finished = 0 async def __executor(self, tid, target): try: connection = self.smb_mgr.create_connection_newtarget(target) async with connection: _, err = await connection.login() if err is not None: raise err res = EnumResult(tid, target) share = SMBShare( name = 'ADMIN$', fullpath = '\\\\%s\\%s' % (connection.target.get_hostname_or_ip(), 'ADMIN$') ) _, err = await share.connect(connection) res.share = True if err is None else False rrp = RRP(connection) _, err = await rrp.connect() res.registry = True if err is None else False srvmgr = SMBRemoteServieManager(connection) _, err = await srvmgr.connect() res.servicemgr = True if err is None else False await self.res_q.put(res) except asyncio.CancelledError: return except Exception as e: await self.res_q.put(EnumResult(tid, target, error = e, status = EnumResultStatus.ERROR)) finally: await self.res_q.put(EnumResult(tid, target, status = EnumResultStatus.FINISHED)) async def worker(self): try: while True: indata = await self.task_q.get() if indata is None: return tid, target = indata try: await asyncio.wait_for(self.__executor(tid, target), timeout=10) except asyncio.CancelledError: return except Exception as e: pass except asyncio.CancelledError: return except Exception as e: return e async def result_processing(self): try: while True: try: er = await self.res_q.get() if er.status == EnumResultStatus.FINISHED: self.__total_finished += 1 print('[P][%s/%s][%s]' % (self.__total_targets, self.__total_finished, 'False')) if self.__total_finished == self.__total_targets and self.__gens_finished is True: print('[P][%s/%s][%s]' % (self.__total_targets, self.__total_finished, 'True')) asyncio.create_task(self.terminate()) return elif er.status == EnumResultStatus.RESULT: print('[R][SHARE][%s][%s][%s]' % (er.target, er.target_id, er.share)) print('[R][REG][%s][%s][%s]' % (er.target, er.target_id, er.registry)) print('[R][SRV][%s][%s][%s]' % (er.target, er.target_id, er.servicemgr)) elif er.status == EnumResultStatus.ERROR: print('[E][%s][%s] %s' % (er.target, er.target_id, er.error)) except asyncio.CancelledError: return except Exception as e: print(e) continue except asyncio.CancelledError: return except Exception as e: print(e) async def terminate(self): for worker in self.workers: worker.cancel() if self.result_processing_task is not None: self.result_processing_task.cancel() async def setup(self): try: if self.res_q is None: self.res_q = asyncio.Queue(self.worker_count) self.result_processing_task = asyncio.create_task(self.result_processing()) if self.task_q is None: self.task_q = asyncio.Queue() for _ in range(self.worker_count): self.workers.append(asyncio.create_task(self.worker())) return True, None except Exception as e: return None, e async def run(self): try: _, err = await self.setup() if err is not None: raise err if self.enum_url is True: if self.smb_mgr.get_target().get_hostname_or_ip() is not None or self.smb_mgr.get_target().get_hostname_or_ip() != '': self.__total_targets += 1 await self.task_q.put((str(uuid.uuid4()), self.smb_mgr.get_target().get_hostname_or_ip())) for target_gen in self.target_gens: total, err = await target_gen.run(self.task_q) self.__total_targets += total if err is not None: print('Target gen error! %s' % err) self.__gens_finished = True await asyncio.gather(*self.workers) return True, None except Exception as e: print(e) return None, e
class SMBPrintnightmareEnum: def __init__(self, smb_url:SMBConnectionURL, worker_count = 10, enum_url = False, out_file = None, show_pbar = True, max_runtime = None, task_q = None, res_q = None, output_type = 'str', ext_result_q = None): self.target_gens = [] self.smb_mgr = smb_url if isinstance(smb_url, str): self.smb_mgr = SMBConnectionURL(smb_url) self.worker_count = worker_count self.task_q = task_q self.res_q = res_q self.workers = [] self.result_processing_task = None self.enum_url = enum_url self.out_file = out_file self.show_pbar = show_pbar self.max_runtime = max_runtime self.output_type = output_type self.ext_result_q = ext_result_q self.write_buffer_size = 1000 self.__gens_finished = False self.__total_targets = 0 self.__total_finished = 0 self.__total_errors = 0 self.__total_sessions = 0 self.__current_targets = {} async def __executor(self, tid, target): try: connection = self.smb_mgr.create_connection_newtarget(target) async with connection: _, err = await connection.login() if err is not None: raise err nonexistentpath = "C:\\doesntexist\\%s.dll" % os.urandom(4).hex() async with SMBMachine(connection) as machine: _, err = await asyncio.wait_for(machine.printnightmare(nonexistentpath, None, silent=True), 10) if err is not None: er = EnumResult(tid, target, 'OK') if str(err).find('ERROR_PATH_NOT_FOUND') != -1: er = EnumResult(tid, target, 'VULN') await self.res_q.put(er) _, err = await asyncio.wait_for(machine.par_printnightmare(nonexistentpath, None, silent=True), 10) if err is not None: er = EnumResult(tid, target, 'OK') if str(err).find('ERROR_PATH_NOT_FOUND') != -1: er = EnumResult(tid, target, 'VULN') await self.res_q.put(er) except asyncio.CancelledError: return except Exception as e: await self.res_q.put(EnumResult(tid, target, None, error = e, status = EnumResultStatus.ERROR)) finally: await self.res_q.put(EnumResult(tid, target, None, status = EnumResultStatus.FINISHED)) async def worker(self): try: while True: indata = await self.task_q.get() if indata is None: return tid, target = indata try: await asyncio.wait_for(self.__executor(tid, target), timeout=self.max_runtime) except asyncio.CancelledError: return except asyncio.TimeoutError as e: await self.res_q.put(EnumResult(tid, target, None, error = e, status = EnumResultStatus.ERROR)) await self.res_q.put(EnumResult(tid, target, None, status = EnumResultStatus.FINISHED)) continue except Exception as e: logger.exception('worker') continue except asyncio.CancelledError: return except Exception as e: return e async def result_processing(self): try: pbar = None if self.show_pbar is True: pbar = {} pbar['targets'] = tqdm(desc='Targets ', unit='', position=0) pbar['vulnerable'] = tqdm(desc='Vulnerable ', unit='', position=1) pbar['connerrors'] = tqdm(desc='Conn Errors ', unit='', position=2) out_buffer = [] final_iter = False while True: try: if self.__gens_finished is True and self.show_pbar is True and pbar['targets'].total is None: pbar['targets'].total = self.__total_targets for key in pbar: pbar[key].refresh() if self.ext_result_q is not None: out_buffer = [] if len(out_buffer) >= self.write_buffer_size or final_iter and self.ext_result_q is None: out_data = '' if self.output_type == 'str': out_data = '\r\n'.join([str(x) for x in out_buffer]) elif self.output_type == 'tsv': for res in out_buffer: x = res.to_tsv() if x == '': continue out_data += '%s\r\n' % x elif self.output_type == 'json': for res in out_buffer: out_data += '%s\r\n' % res.to_json() else: out_data = '\r\n'.join(out_buffer) if self.out_file is not None: with open(self.out_file, 'a+', newline = '') as f: f.write(out_data) else: print(out_data) if self.show_pbar is True: for key in pbar: pbar[key].refresh() out_buffer = [] out_data = '' if final_iter: asyncio.create_task(self.terminate()) return try: er = await asyncio.wait_for(self.res_q.get(), timeout = 5) except asyncio.TimeoutError: if self.show_pbar is True: for key in pbar: pbar[key].refresh() if self.__total_finished == self.__total_targets and self.__gens_finished is True: final_iter = True continue if er.status == EnumResultStatus.FINISHED: self.__total_finished += 1 if self.show_pbar is True: pbar['targets'].update(1) obj = EnumProgress(self.__total_targets, self.__total_finished, self.__gens_finished, er.target) if self.ext_result_q is not None: await self.ext_result_q.put(EnumResultFinal(obj, 'progress', None, er.target, er.target_id)) out_buffer.append(EnumResultFinal(obj, 'progress', None, er.target, er.target_id)) if self.__total_finished == self.__total_targets and self.__gens_finished is True: final_iter = True continue if er.result is not None: if self.ext_result_q is not None: await self.ext_result_q.put(EnumResultFinal(er.result, 'result', None, er.target, er.target_id)) out_buffer.append(EnumResultFinal(er.result, 'result', None, er.target, er.target_id)) self.__total_sessions += 1 if self.show_pbar is True and er.result.startswith('VULN') is True: pbar['vulnerable'].update(1) if er.status == EnumResultStatus.ERROR: self.__total_errors += 1 if self.show_pbar is True: pbar['connerrors'].update(1) except asyncio.CancelledError: return except Exception as e: logger.exception('result_processing inner') asyncio.create_task(self.terminate()) return except asyncio.CancelledError: return except Exception as e: logger.exception('result_processing') asyncio.create_task(self.terminate()) finally: if self.ext_result_q is not None: await self.ext_result_q.put(EnumResultFinal(None, 'finished', None, None, None)) async def terminate(self): for worker in self.workers: worker.cancel() if self.result_processing_task is not None: self.result_processing_task.cancel() async def setup(self): try: if self.res_q is None: self.res_q = asyncio.Queue(self.worker_count) self.result_processing_task = asyncio.create_task(self.result_processing()) if self.task_q is None: self.task_q = asyncio.Queue(self.worker_count) for _ in range(self.worker_count): self.workers.append(asyncio.create_task(self.worker())) return True, None except Exception as e: return None, e async def __generate_targets(self): if self.enum_url is True: self.__total_targets += 1 await self.task_q.put((str(uuid.uuid4()), self.smb_mgr.get_target().get_hostname_or_ip())) for target_gen in self.target_gens: async for uid, target, err in target_gen.generate(): if err is not None: print('Target gen error! %s' % err) break self.__total_targets += 1 await self.task_q.put((uid, target)) await asyncio.sleep(0) self.__gens_finished = True async def run(self): try: _, err = await self.setup() if err is not None: raise err gen_task = asyncio.create_task(self.__generate_targets()) await asyncio.gather(*self.workers) await self.result_processing_task return True, None except Exception as e: logger.exception('run') return None, e
class SMBGET: def __init__(self, smb_url, show_progress=False): self.smb_mgr = SMBConnectionURL(smb_url) self.target_gens = [] self.task_q = None self.__total_targets = 0 self.target_gen_task = None self.show_progress = show_progress async def __target_gen(self): for target_gen in self.target_gens: total, err = await target_gen.run(self.task_q) self.__total_targets += total if err is not None: print('Target gen error! %s' % err) await self.task_q.put(None) async def run(self): try: self.task_q = asyncio.Queue() self.target_gen_task = asyncio.create_task(self.__target_gen()) while True: t = await self.task_q.get() if t is None: return True, None tid, target = t unc = PureWindowsPath(target) file_name = unc.name print() connection = self.smb_mgr.create_connection_newtarget( target.replace('\\\\', '').split('\\')[0]) async with connection: _, err = await connection.login() if err is not None: raise err print(target) smbfile = SMBFile.from_uncpath(target) _, err = await smbfile.open(connection, 'r') if err is not None: logger.info('Error Downloading file %s' % target) continue if self.show_progress is True: pbar = tqdm.tqdm(desc='Downloading %s' % file_name, total=smbfile.size, unit='B', unit_scale=True, unit_divisor=1024) with open(file_name, 'wb') as f: async for data, err in smbfile.read_chunked(): if err is not None: logger.info('Error Downloading file %s' % target) continue if data is None: break f.write(data) if self.show_progress is True: pbar.update(len(data)) return True, None except Exception as e: return False, e
async def amain(): import argparse parser = argparse.ArgumentParser(description='Secretsdump') parser.add_argument('-v', '--verbose', action='count', default=0) parser.add_argument('-t', '--target-file', help='file with target hosts, one per line.') parser.add_argument( '-o', '--output-folder', default='results', help= 'file to write all results to. please use full path, will create new directories recursively!' ) parser.add_argument('-w', '--worker-count', type=int, default=50, help='Maximum worker count') parser.add_argument( '-b', '--bin-folder', default='bins', help= 'Location of the binary utils folder. (where procdump.exe and procdump64.exe is)' ) parser.add_argument('cmd', choices=['dcsync', 'registry', 'lsass', 'all']) parser.add_argument('smb_url', help='the SMB connection URL string') args = parser.parse_args() worker_tasks = [] process_q = asyncio.Queue() out_q = asyncio.Queue() #creating results directory output_root = Path(args.output_folder) output_root.mkdir(parents=True, exist_ok=True) connections = [] # checking if SMB url is parsable connection_url = SMBConnectionURL(args.smb_url) connections.append(connection_url.get_connection()) for _ in range(min(len(connections), args.worker_count)): wt = asyncio.create_task(worker(process_q, out_q, args, output_root)) worker_tasks.append(wt) # parsing targets if args.target_file is not None: with open(args.target_file, 'r') as f: for line in f: line = line.strip() connection = connection_url.create_connection_newtarget(line) connections.append(connection) # main for connection in connections: await process_q.put(connection) for _ in range(len(worker_tasks)): await process_q.put(None) finished_workers = 0 while True: res = await out_q.get() if res is None: finished_workers += 1 if finished_workers >= len(worker_tasks): break print('Done!')
class SMBFileEnum: def __init__(self, smb_url, worker_count=100, depth=3, enum_url=True): self.target_gens = [] self.smb_mgr = SMBConnectionURL(smb_url) self.worker_count = worker_count self.task_q = None self.res_q = None self.depth = depth self.workers = [] self.result_processing_task = None self.enum_url = enum_url self.__gens_finished = False self.__total_targets = 0 self.__total_finished = 0 async def __executor(self, tid, target): try: connection = self.smb_mgr.create_connection_newtarget(target) async with connection: _, err = await connection.login() if err is not None: raise err machine = SMBMachine(connection) async for path, otype, err in machine.enum_all_recursively( depth=self.depth): er = EnumResult(tid, target, (path, otype, err)) await self.res_q.put(er) except asyncio.CancelledError: return except Exception as e: await self.res_q.put( EnumResult(tid, target, None, error=e, status=EnumResultStatus.ERROR)) finally: await self.res_q.put( EnumResult(tid, target, None, status=EnumResultStatus.FINISHED)) async def worker(self): try: while True: indata = await self.task_q.get() if indata is None: return tid, target = indata try: await asyncio.wait_for(self.__executor(tid, target), timeout=10) except asyncio.CancelledError: return except Exception as e: pass except asyncio.CancelledError: return except Exception as e: return e async def result_processing(self): try: while True: try: er = await self.res_q.get() if er.status == EnumResultStatus.FINISHED: self.__total_finished += 1 print('[P][%s/%s][%s]' % (self.__total_targets, self.__total_finished, str(self.__gens_finished))) if self.__total_finished == self.__total_targets and self.__gens_finished is True: asyncio.create_task(self.terminate()) return if er.result is not None: path, otype, err = er.result if otype is not None: print('[%s] %s' % (otype[0].upper(), path)) if err is not None: print('[E] %s %s' % (err, path)) except asyncio.CancelledError: return except Exception as e: print(e) continue except asyncio.CancelledError: return except Exception as e: print(e) async def terminate(self): for worker in self.workers: worker.cancel() if self.result_processing_task is not None: self.result_processing_task.cancel() async def setup(self): try: if self.res_q is None: self.res_q = asyncio.Queue(self.worker_count) self.result_processing_task = asyncio.create_task( self.result_processing()) if self.task_q is None: self.task_q = asyncio.Queue() for _ in range(self.worker_count): self.workers.append(asyncio.create_task(self.worker())) return True, None except Exception as e: return None, e async def run(self): try: _, err = await self.setup() if err is not None: raise err if self.enum_url is True: self.__total_targets += 1 await self.task_q.put( (str(uuid.uuid4()), self.smb_mgr.get_target().get_hostname_or_ip())) for target_gen in self.target_gens: total, err = await target_gen.run(self.task_q) self.__total_targets += total if err is not None: print('Target gen error! %s' % err) self.__gens_finished = True await asyncio.gather(*self.workers) return True, None except Exception as e: print(e) return None, e
async def lsassdump(url, method='task', remote_base_path='C:\\Windows\\Temp\\', remote_share_name='\\c$\\Windows\\Temp\\', chunksize=64 * 1024, packages=['all'], targets=[], worker_cnt=5): from aiosmb.commons.connection.url import SMBConnectionURL base_url = None base_conn = None mimis = [] workers = [] tgens = [] if targets is not None and len(targets) != 0: notfile = [] if targets is not None: for target in targets: try: f = open(target, 'r') f.close() tgens.append(FileTargetGen(target)) except: notfile.append(target) if len(notfile) > 0: tgens.append(ListTargetGen(notfile)) if isinstance(url, SMBConnectionURL): base_url = url base_conn = url.get_connection() else: base_url = SMBConnectionURL(url) base_conn = base_url.get_connection() lsassdump_coro = lsassdump_single(base_conn.target.get_hostname_or_ip(), base_conn, method=method, remote_base_path=remote_base_path, remote_share_name=remote_share_name, chunksize=chunksize, packages=packages) workers.append(lsassdump_coro) for tgen in tgens: async for _, target, err in tgen.generate(): tconn = base_url.create_connection_newtarget(target) lsassdump_coro = lsassdump_single( tconn.target.get_hostname_or_ip(), tconn, method=method, remote_base_path=remote_base_path, remote_share_name=remote_share_name, chunksize=chunksize, packages=packages) workers.append(lsassdump_coro) if len(workers) >= worker_cnt: tres = await asyncio.gather(*workers) for res in tres: yield res workers = [] if len(workers) > 0: tres = await asyncio.gather(*workers) for res in tres: yield res workers = []
async def regdump(url, hives=['HKLM\\SAM', 'HKLM\\SYSTEM', 'HKLM\\SECURITY'], remote_base_path='C:\\Windows\\Temp\\', remote_share_name='\\c$\\Windows\\Temp\\', enable_wait=3, targets=[], worker_cnt=5): from aiosmb.commons.connection.url import SMBConnectionURL base_url = None base_conn = None mimis = [] workers = [] tgens = [] if targets is not None and len(targets) != 0: notfile = [] if targets is not None: for target in targets: try: f = open(target, 'r') f.close() tgens.append(FileTargetGen(target)) except: notfile.append(target) if len(notfile) > 0: tgens.append(ListTargetGen(notfile)) if isinstance(url, SMBConnectionURL): base_url = url base_conn = url.get_connection() else: base_url = SMBConnectionURL(url) base_conn = base_url.get_connection() regdump_coro = regdump_single(base_conn.target.get_hostname_or_ip(), base_conn, hives=hives, remote_base_path=remote_base_path, remote_share_name=remote_share_name, enable_wait=enable_wait) workers.append(regdump_coro) for tgen in tgens: async for _, target, err in tgen.generate(): tconn = base_url.create_connection_newtarget(target) regdump_coro = regdump_single(tconn.target.get_hostname_or_ip(), tconn, hives=hives, remote_base_path=remote_base_path, remote_share_name=remote_share_name, enable_wait=enable_wait) workers.append(regdump_coro) if len(workers) >= worker_cnt: tres = await asyncio.gather(*workers) for res in tres: yield res workers = [] if len(workers) > 0: tres = await asyncio.gather(*workers) for res in tres: yield res workers = []
class SMBAdminCheck: def __init__(self, smb_url, worker_count=100, enum_url=True, exclude_target=[], show_pbar=False, ext_result_q=None, output_type='str', out_file=None): self.target_gens = [] self.smb_mgr = SMBConnectionURL(smb_url) self.worker_count = worker_count self.task_q = None self.res_q = None self.workers = [] self.result_processing_task = None self.enum_url = enum_url self.exclude_target = [] self.show_pbar = show_pbar self.ext_result_q = ext_result_q self.output_type = output_type self.out_file = out_file self.__gens_finished = False self.__total_targets = 0 self.__total_finished = 0 async def __executor(self, tid, target): try: connection = self.smb_mgr.create_connection_newtarget(target) async with connection: _, err = await connection.login() if err is not None: raise err res = SMBAdminEnumResultInner(tid, target) share = SMBShare( name='ADMIN$', fullpath='\\\\%s\\%s' % (connection.target.get_hostname_or_ip(), 'ADMIN$')) _, err = await share.connect(connection) res.share = True if err is None else False rrp = RRP(connection) _, err = await rrp.connect() res.registry = True if err is None else False srvmgr = SMBRemoteServieManager(connection) _, err = await srvmgr.connect() res.servicemgr = True if err is None else False await self.res_q.put(res) except asyncio.CancelledError: return except Exception as e: await self.res_q.put( SMBAdminEnumResultInner(tid, target, error=e, status=EnumResultStatus.ERROR)) finally: await self.res_q.put( SMBAdminEnumResultInner(tid, target, status=EnumResultStatus.FINISHED)) async def worker(self): try: while True: indata = await self.task_q.get() if indata is None: return tid, target = indata try: await asyncio.wait_for(self.__executor(tid, target), timeout=10) except asyncio.CancelledError: return except Exception as e: logger.debug('worker Error %s' % e) continue except asyncio.CancelledError: return except Exception as e: return e async def result_processing(self): try: pbar = None if self.show_pbar is True: pbar = {} pbar['targets'] = tqdm(desc='Targets ', unit='', position=0) pbar['share'] = tqdm(desc='C$ Access ', unit='', position=1) pbar['reg'] = tqdm(desc='Registry Access', unit='', position=2) pbar['svc'] = tqdm(desc='Service Access', unit='', position=3) pbar['connerrors'] = tqdm(desc='Conn Errors ', unit='', position=4) out_buffer = [] final_iter = False while True: try: if self.__gens_finished is True and self.show_pbar is True and pbar[ 'targets'].total is None: pbar['targets'].total = self.__total_targets for key in pbar: pbar[key].refresh() if self.ext_result_q is not None: out_buffer = [] if len( out_buffer ) >= 1000 or final_iter and self.ext_result_q is None: out_data = '' if self.output_type == 'str': out_data = '\r\n'.join( [str(x) for x in out_buffer]) elif self.output_type == 'tsv': for res in out_buffer: x = res.to_tsv() if x is not None and len(x) > 0: out_data += '%s\r\n' % x elif self.output_type == 'json': for res in out_buffer: out_data += '%s\r\n' % res.to_json() else: out_data = '\r\n'.join(out_buffer) if self.out_file is not None: with open(self.out_file, 'a+', newline='') as f: f.write(out_data) else: print(out_data) if self.show_pbar is True: for key in pbar: pbar[key].refresh() out_buffer = [] out_data = '' if final_iter: asyncio.create_task(self.terminate()) return try: er = await asyncio.wait_for(self.res_q.get(), timeout=5) except asyncio.TimeoutError: if self.show_pbar is True: for key in pbar: pbar[key].refresh() if self.__total_finished == self.__total_targets and self.__gens_finished is True: final_iter = True continue if er.status == EnumResultStatus.FINISHED: self.__total_finished += 1 if self.show_pbar is True: pbar['targets'].update(1) obj = SMBAdminEnumProgressResult( self.__total_targets, self.__total_finished, self.__gens_finished, er.target) if self.ext_result_q is not None: await self.ext_result_q.put( SMBAdminEnumResult(obj, 'progress')) out_buffer.append(SMBAdminEnumResult(obj, 'progress')) if self.__total_finished == self.__total_targets and self.__gens_finished is True: final_iter = True continue elif er.status == EnumResultStatus.RESULT: if self.show_pbar is True: if er.share is True: pbar['share'].update(1) if er.registry is True: pbar['reg'].update(1) if er.servicemgr is True: pbar['svc'].update(1) if self.ext_result_q is not None: await self.ext_result_q.put( SMBAdminEnumResult(er, 'result')) out_buffer.append(SMBAdminEnumResult(er, 'result')) elif er.status == EnumResultStatus.ERROR: if self.ext_result_q is not None: await self.ext_result_q.put( SMBAdminEnumResult(er, 'error')) if self.show_pbar is True: pbar['connerrors'].update(1) out_buffer.append(SMBAdminEnumResult(er, 'error')) except asyncio.CancelledError: return except Exception as e: logger.exception('result_processing inner') continue except asyncio.CancelledError: return except Exception as e: logger.exception('result_processing main') async def terminate(self): for worker in self.workers: worker.cancel() if self.result_processing_task is not None: self.result_processing_task.cancel() async def setup(self): try: if self.res_q is None: self.res_q = asyncio.Queue(self.worker_count) self.result_processing_task = asyncio.create_task( self.result_processing()) if self.task_q is None: self.task_q = asyncio.Queue() for _ in range(self.worker_count): self.workers.append(asyncio.create_task(self.worker())) return True, None except Exception as e: return None, e async def __generate_targets(self): if self.enum_url is True: self.__total_targets += 1 await self.task_q.put( (str(uuid.uuid4()), self.smb_mgr.get_target().get_hostname_or_ip())) for target_gen in self.target_gens: async for uid, target, err in target_gen.generate(): if err is not None: print('Target gen error! %s' % err) break if target in self.exclude_target: continue self.__total_targets += 1 await self.task_q.put((uid, target)) await asyncio.sleep(0) self.__gens_finished = True async def run(self): try: _, err = await self.setup() if err is not None: raise err gen_task = asyncio.create_task(self.__generate_targets()) await asyncio.gather(*self.workers) await self.result_processing_task return True, None except Exception as e: print(e) return None, e
class SMBFileEnum: def __init__(self, smb_url, worker_count=10, depth=3, enum_url=False, out_file=None, show_pbar=True, max_items=None, max_runtime=None, fetch_share_sd=False, fetch_dir_sd=False, fetch_file_sd=False, task_q=None, res_q=None, output_type='str', exclude_share=[], exclude_dir=[], exclude_target=[], ext_result_q=None): self.target_gens = [] self.smb_mgr = SMBConnectionURL(smb_url) self.worker_count = worker_count self.task_q = task_q self.res_q = res_q self.depth = depth self.workers = [] self.result_processing_task = None self.enum_url = enum_url self.out_file = out_file self.show_pbar = show_pbar self.max_items = max_items self.max_runtime = max_runtime self.fetch_share_sd = fetch_share_sd self.fetch_dir_sd = fetch_dir_sd self.fetch_file_sd = fetch_file_sd self.output_type = output_type self.exclude_share = exclude_share self.exclude_dir = exclude_dir self.exclude_target = exclude_target self.ext_result_q = ext_result_q self.__gens_finished = False self.__total_targets = 0 self.__total_finished = 0 self.__total_size = 0 self.__total_shares = 0 self.__total_dirs = 0 self.__total_files = 0 self.__total_errors = 0 self.__current_targets = {} async def __executor(self, tid, target): try: connection = self.smb_mgr.create_connection_newtarget(target) async with connection: _, err = await connection.login() if err is not None: raise err machine = SMBMachine(connection) async for obj, otype, err in machine.enum_all_recursively( depth=self.depth, maxentries=self.max_items, fetch_share_sd=self.fetch_share_sd, fetch_dir_sd=self.fetch_dir_sd, fetch_file_sd=self.fetch_file_sd, exclude_share=self.exclude_share, exclude_dir=self.exclude_dir): er = EnumResult(tid, target, (obj, otype, err)) await self.res_q.put(er) except asyncio.CancelledError: return except Exception as e: await self.res_q.put( EnumResult(tid, target, None, error=e, status=EnumResultStatus.ERROR)) finally: await self.res_q.put( EnumResult(tid, target, None, status=EnumResultStatus.FINISHED)) async def worker(self): try: while True: indata = await self.task_q.get() if indata is None: return tid, target = indata try: await asyncio.wait_for(self.__executor(tid, target), timeout=self.max_runtime) except asyncio.CancelledError: return except asyncio.TimeoutError as e: await self.res_q.put( EnumResult(tid, target, None, error=e, status=EnumResultStatus.ERROR)) await self.res_q.put( EnumResult(tid, target, None, status=EnumResultStatus.FINISHED)) continue except Exception as e: logger.exception('worker') continue except asyncio.CancelledError: return except Exception as e: return e async def result_processing(self): try: pbar = None if self.show_pbar is True: pbar = {} pbar['targets'] = tqdm(desc='Targets ', unit='', position=0) pbar['shares'] = tqdm(desc='Shares ', unit='', position=1) pbar['dirs'] = tqdm(desc='Dirs ', unit='', position=2) pbar['files'] = tqdm(desc='Files ', unit='', position=3) pbar['filesize'] = tqdm(desc='Files (size)', unit='B', unit_scale=True, position=4) pbar['maxed'] = tqdm(desc='Maxed ', unit='', position=5) pbar['enumerrors'] = tqdm(desc='Enum Errors ', unit='', position=6) pbar['connerrors'] = tqdm(desc='Conn Errors ', unit='', position=7) out_buffer = [] final_iter = False while True: try: if self.__gens_finished is True and self.show_pbar is True and pbar[ 'targets'].total is None: pbar['targets'].total = self.__total_targets for key in pbar: pbar[key].refresh() if self.ext_result_q is not None: out_buffer = [] if len( out_buffer ) >= 1000 or final_iter and self.ext_result_q is None: out_data = '' if self.output_type == 'str': out_data = '\r\n'.join( [str(x) for x in out_buffer]) elif self.output_type == 'tsv': for res in out_buffer: out_data += '%s\r\n' % res.to_tsv() elif self.output_type == 'json': for res in out_buffer: out_data += '%s\r\n' % res.to_json() else: out_data = '\r\n'.join(out_buffer) if self.out_file is not None: with open(self.out_file, 'a+', newline='') as f: try: f.write(out_data) except: for line in out_data.split('\r\n'): try: f.write(line + '\r\n') except: logger.debug( 'Encoding issue, skipping a line' ) continue else: print(out_data) if self.show_pbar is True: for key in pbar: pbar[key].refresh() out_buffer = [] out_data = '' if final_iter: asyncio.create_task(self.terminate()) return try: er = await asyncio.wait_for(self.res_q.get(), timeout=5) except asyncio.TimeoutError: if self.show_pbar is True: for key in pbar: pbar[key].refresh() if self.__total_finished == self.__total_targets and self.__gens_finished is True: final_iter = True continue if er.status == EnumResultStatus.FINISHED: self.__total_finished += 1 if self.show_pbar is True: pbar['targets'].update(1) obj = EnumProgress(self.__total_targets, self.__total_finished, self.__gens_finished, er.target) if self.ext_result_q is not None: await self.ext_result_q.put( EnumResultFinal(obj, 'progress', None, er.target, er.target_id)) out_buffer.append( EnumResultFinal(obj, 'progress', None, er.target, er.target_id)) if self.__total_finished == self.__total_targets and self.__gens_finished is True: final_iter = True continue if er.result is not None: obj, otype, err = er.result if self.ext_result_q is not None: await self.ext_result_q.put( EnumResultFinal(obj, otype, err, er.target, er.target_id)) out_buffer.append( EnumResultFinal(obj, otype, err, er.target, er.target_id)) if otype is not None: if otype == 'file': self.__total_files += 1 if isinstance( obj.size, int) is True: #just making sure... self.__total_size += obj.size if self.show_pbar is True: pbar['filesize'].update(obj.size) elif otype == 'dir': self.__total_dirs += 1 elif otype == 'share': self.__total_shares += 1 if self.show_pbar is True: if otype == 'dir': pbar['dirs'].update(1) elif otype == 'file': pbar['files'].update(1) elif otype == 'share': pbar['shares'].update(1) elif otype == 'maxed': pbar['maxed'].update(1) if err is not None: self.__total_errors += 1 if self.show_pbar is True: pbar['enumerrors'].update(1) if er.status == EnumResultStatus.ERROR: self.__total_errors += 1 if self.show_pbar is True: pbar['connerrors'].update(1) except asyncio.CancelledError: return except Exception as e: logger.exception('result_processing inner') asyncio.create_task(self.terminate()) return except asyncio.CancelledError: return except Exception as e: logger.exception('result_processing') asyncio.create_task(self.terminate()) finally: if self.ext_result_q is not None: await self.ext_result_q.put( EnumResultFinal(None, 'finished', None, None, None)) async def terminate(self): for worker in self.workers: worker.cancel() if self.result_processing_task is not None: self.result_processing_task.cancel() async def setup(self): try: if self.res_q is None: self.res_q = asyncio.Queue(self.worker_count) self.result_processing_task = asyncio.create_task( self.result_processing()) if self.task_q is None: self.task_q = asyncio.Queue(self.worker_count) for _ in range(self.worker_count): self.workers.append(asyncio.create_task(self.worker())) return True, None except Exception as e: return None, e async def __generate_targets(self): if self.enum_url is True: self.__total_targets += 1 await self.task_q.put( (str(uuid.uuid4()), self.smb_mgr.get_target().get_hostname_or_ip())) for target_gen in self.target_gens: async for uid, target, err in target_gen.generate(): if err is not None: print('Target gen error! %s' % err) break if target in self.exclude_target: continue self.__total_targets += 1 await self.task_q.put((uid, target)) await asyncio.sleep(0) self.__gens_finished = True async def run(self): try: _, err = await self.setup() if err is not None: raise err gen_task = asyncio.create_task(self.__generate_targets()) await asyncio.gather(*self.workers) await self.result_processing_task return True, None except Exception as e: logger.exception('run') return None, e