async def filereader_test(connection_string, filename, proxy=None): #target = SMBTarget.from_connection_string(connection_string) #if proxy is not None: # target.proxy = SMBTargetProxy.from_connection_string(proxy) # print(str(target)) # #credential = SMBCredential.from_connection_string(connection_string) cu = SMBConnectionURL(connection_string) credential = cu.get_credential() target = cu.get_target() print(credential) print(target) input() spneg = AuthenticatorBuilder.to_spnego_cred(credential, target) async with SMBConnection(spneg, target) as connection: await connection.login() async with SMBFileReader(connection) as reader: await reader.open(filename) data = await reader.read() print(data) """
class SMBClient(aiocmd.PromptToolkitCmd): def __init__(self, url = None, silent = False, no_dce = False): aiocmd.PromptToolkitCmd.__init__(self, ignore_sigint=False) #Setting this to false, since True doesnt work on windows... self.conn_url = None if url is not None: self.conn_url = SMBConnectionURL(url) self.connection = None self.machine = None self.is_anon = False self.silent = silent self.no_dce = no_dce # diables ANY use of the DCE protocol (eg. share listing) This is useful for new(er) windows servers where they forbid the users to use any form of DCE self.shares = {} #name -> share self.__current_share = None self.__current_directory = None async def do_coninfo(self): try: from aiosmb._version import __version__ as smbver from asysocks._version import __version__ as socksver from minikerberos._version import __version__ as kerbver from winsspi._version import __version__ as winsspiver from winacl._version import __version__ as winaclver print(self.conn_url) print('AIOSMB: %s' % smbver) print('ASYSOCKS: %s' % socksver) print('MINIKERBEROS: %s' % kerbver) print('WINSSPI: %s' % winsspiver) print('WINACL: %s' % winaclver) return True, None except Exception as e: traceback.print_exc() return None, e async def do_login(self, url = None): """Connects to the remote machine""" try: if self.conn_url is None and url is None: print('No url was set, cant do logon') if url is not None: self.conn_url = SMBConnectionURL(url) cred = self.conn_url.get_credential() if cred.secret is None and cred.username is None and cred.domain is None: self.is_anon = True self.connection = self.conn_url.get_connection() logger.debug(self.conn_url.get_credential()) logger.debug(self.conn_url.get_target()) _, err = await self.connection.login() if err is not None: raise err self.machine = SMBMachine(self.connection) if self.silent is False: print('Login success') return True, None except Exception as e: traceback.print_exc() print('Login failed! Reason: %s' % str(e)) return False, e async def do_logout(self): if self.machine is not None: await self.machine.close() self.machine = None if self.connection is not None: try: await self.connection.terminate() except Exception as e: logger.exception('connection.close') self.connection = None async def _on_close(self): await self.do_logout() async def do_nodce(self): """Disables automatic share listing on login""" self.no_dce = True async def do_shares(self, show = True): """Lists available shares""" try: if self.machine is None: print('Not logged in! Use "login" first!') return False, Exception('Not logged in!') async for share, err in self.machine.list_shares(): if err is not None: raise err self.shares[share.name] = share if show is True: print(share.name) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_sessions(self): """Lists sessions of connected users""" try: async for sess, err in self.machine.list_sessions(): if err is not None: raise err print("%s : %s" % (sess.username, sess.ip_addr)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_wsessions(self): """Lists sessions of connected users""" try: async for sess, err in self.machine.wkstlist_sessions(): if err is not None: raise err print("%s" % sess.username) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_domains(self): """Lists domain""" try: async for domain, err in self.machine.list_domains(): if err is not None: raise err print(domain) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_localgroups(self): """Lists local groups""" try: async for name, sid, err in self.machine.list_localgroups(): if err is not None: raise err print("%s : %s" % (name, sid)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_domaingroups(self, domain_name): """Lists groups in a domain""" try: async for name, sid, err in self.machine.list_groups(domain_name): if err is not None: raise err print("%s : %s" % (name, sid)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_groupmembers(self, domain_name, group_name): """Lists members of an arbitrary group""" try: async for domain, username, sid, err in self.machine.list_group_members(domain_name, group_name): if err is not None: raise err print("%s\\%s : %s" % (domain, username, sid)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_localgroupmembers(self, group_name): """Lists members of a local group""" try: async for domain, username, sid, err in self.machine.list_group_members('Builtin', group_name): if err is not None: raise err print("%s\\%s : %s" % (domain, username, sid)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_addsidtolocalgroup(self, group_name, sid): """Add member (by SID) to a local group""" try: result, err = await self.machine.add_sid_to_group('Builtin', group_name, sid) if err is not None: raise err if result: print('Modification OK!') else: print('Something went wrong, status != ok') except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_use(self, share_name): """selects share to be used""" try: if self.is_anon is False or self.no_dce: #anonymous connection might not have access to IPC$ so we are skipping the check if len(self.shares) == 0: _, err = await self.do_shares(show = False) if err is not None: raise err if share_name not in self.shares: if share_name.upper() not in self.shares: print('Error! Uknown share name %s' % share_name) return share_name = share_name.upper() self.__current_share = self.shares[share_name] else: self.__current_share = SMBShare.from_unc('\\\\%s\\%s' % (self.connection.target.get_hostname_or_ip(), share_name)) _, err = await self.__current_share.connect(self.connection) if err is not None: raise err self.__current_directory = self.__current_share.subdirs[''] #this is the entry directory self.prompt = '[%s]$ ' % self.__current_directory.unc_path _, err = await self.do_refreshcurdir() if err is not None: raise err return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_dir(self): return await self.do_ls() async def do_ls(self): try: if self.__current_share is None: print('No share selected!') return if self.__current_directory is None: print('No directory selected!') return for entry in self.__current_directory.get_console_output(): print(entry) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_refreshcurdir(self): try: async for entry in self.machine.list_directory(self.__current_directory): #no need to put here anything, the dir bject will store the refreshed data a = 1 return True, None except Exception as e: traceback.print_exc() return None, e async def do_cd(self, directory_name): try: if self.__current_share is None: print('No share selected!') return False, None if self.__current_directory is None: print('No directory selected!') return False, None if directory_name not in self.__current_directory.subdirs: if directory_name == '..': self.__current_directory = self.__current_directory.parent_dir self.prompt = '[%s] $' % (self.__current_directory.unc_path) return True, None else: print('The directory "%s" is not in parent directory "%s"' % (directory_name, self.__current_directory.fullpath)) return False, None else: self.__current_directory = self.__current_directory.subdirs[directory_name] self.prompt = '[%s] $' % (self.__current_directory.unc_path) _, err = await self.do_refreshcurdir() if err is not None: raise err return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e def get_current_dirs(self): if self.__current_directory is None: return [] return list(self.__current_directory.subdirs.keys()) def get_current_files(self): if self.__current_directory is None: return [] return list(self.__current_directory.files.keys()) async def do_getfilesd(self, file_name): try: if file_name not in self.__current_directory.files: print('file not in current directory!') return False, None file_obj = self.__current_directory.files[file_name] sd, err = await file_obj.get_security_descriptor(self.connection) if err is not None: raise err print(sd.to_sddl()) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_getdirsd(self): try: sd, err = await self.__current_directory.get_security_descriptor(self.connection) if err is not None: raise err print(str(sd.to_sddl())) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e def _cd_completions(self): return SMBPathCompleter(get_current_dirs = self.get_current_dirs) def _get_completions(self): return SMBPathCompleter(get_current_dirs = self.get_current_files) def _del_completions(self): return SMBPathCompleter(get_current_dirs = self.get_current_files) def _sid_completions(self): return SMBPathCompleter(get_current_dirs = self.get_current_files) def _dirsid_completions(self): return SMBPathCompleter(get_current_dirs = self.get_current_dirs) async def do_services(self): """Lists remote services""" try: async for service, err in self.machine.list_services(): if err is not None: raise err print(service) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_serviceen(self, service_name): """Enables a remote service""" try: res, err = await self.machine.enable_service(service_name) if err is not None: raise err print(res) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_servicecreate(self, service_name, command, display_name = None): """Creates a remote service""" try: _, err = await self.machine.create_service(service_name, command, display_name) if err is not None: raise err print('Service created!') return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_servicecmdexec(self, command, timeout = 1): """Executes a shell command as a service and returns the result""" try: buffer = b'' if timeout is None or timeout == '': timeout = 1 timeout = int(timeout) async for data, err in self.machine.service_cmd_exec(command): if err is not None: raise err if data is None: break try: print(data.decode()) except: print(data) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_servicedeploy(self, path_to_exec, remote_path): """Deploys a binary file from the local system as a service on the remote system""" #servicedeploy /home/devel/Desktop/cmd.exe /shared/a.exe try: basename = ntpath.basename(remote_path) remote_path = '\\\\%s\\%s\\%s\\%s' % (self.connection.target.get_hostname_or_ip(), self.__current_share.name, self.__current_directory.fullpath , basename) _, err = await self.machine.deploy_service(path_to_exec, remote_path = remote_path) if err is not None: raise err print('Service deployed!') return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_put(self, file_name): """Uploads a file to the remote share""" try: basename = ntpath.basename(file_name) dst = '\\%s\\%s\\%s' % (self.__current_share.name, self.__current_directory.fullpath , basename) _, err = await self.machine.put_file(file_name, dst) if err is not None: print('Failed to put file! Reason: %s' % err) return False, err print('File uploaded!') _, err = await self.do_refreshcurdir() if err is not None: raise err return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_del(self, file_name): """Removes a file from the remote share""" try: basename = ntpath.basename(file_name) dst = '\\%s\\%s\\%s' % (self.__current_share.name, self.__current_directory.fullpath , basename) _, err = await self.machine.del_file(dst) if err is not None: raise err print('File deleted!') _, err = await self.do_refreshcurdir() if err is not None: raise err return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_regsave(self, hive_name, file_path): """Saves a registry hive to a file on remote share""" try: _, err = await self.machine.save_registry_hive(hive_name, file_path) if err is not None: raise err print('Hive saved!') return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_reglistusers(self): """Saves a registry hive to a file on remote share""" try: users, err = await self.machine.reg_list_users() if err is not None: raise err for user in users: print(user) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_get(self, file_name): """Download a file from the remote share to the current folder""" try: matched = [] if file_name not in self.__current_directory.files: for fn in fnmatch.filter(list(self.__current_directory.files.keys()), file_name): matched.append(fn) if len(matched) == 0: print('File with name %s is not present in the directory %s' % (file_name, self.__current_directory.name)) return False, None else: matched.append(file_name) for file_name in matched: file_obj = self.__current_directory.files[file_name] with tqdm.tqdm(desc = 'Downloading %s' % file_name, total=file_obj.size, unit='B', unit_scale=True, unit_divisor=1024) as pbar: with open(file_name, 'wb') as outfile: async for data, err in self.machine.get_file_data(file_obj): if err is not None: raise err if data is None: break outfile.write(data) pbar.update(len(data)) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_mkdir(self, directory_name): """Creates a directory on the remote share""" try: _, err = await self.machine.create_subdirectory(directory_name, self.__current_directory) if err is not None: raise err print('Directory created!') _, err = await self.do_refreshcurdir() if err is not None: raise err return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_dcsync(self, username = None): """It's a suprse tool that will help us later""" try: users = [] if username is not None: users.append(username) async for secret, err in self.machine.dcsync(target_users=users): if err is not None: raise err if secret is None: continue print(str(secret)) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_users(self, domain = None): """List users in domain""" try: async for username, user_sid, err in self.machine.list_domain_users(domain): if err is not None: print(str(err)) print('%s %s' % (username, user_sid)) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_lsass(self): try: res, err = await self.machine.task_dump_lsass() if err is not None: print(str(err)) print(res) await res.close() return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e async def do_printerbug(self, attacker_ip): """Printerbug""" try: res, err = await self.machine.printerbug(attacker_ip) if err is not None: print(str(err)) print(res) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_tasks(self): """List scheduled tasks """ try: async for taskname, err in self.machine.tasks_list(): if err is not None: raise err print(taskname) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_taskregister(self, template_file, task_name = None): """Registers a new scheduled task""" try: with open(template_file, 'r') as f: template = f.read() res, err = await self.machine.tasks_register(template, task_name = task_name) if err is not None: logger.info('[!] Failed to register new task!') raise err return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_taskdel(self, task_name): """Deletes a scheduled task """ try: _, err = await self.machine.tasks_delete(task_name) if err is not None: raise err return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_taskcmdexec(self, command, timeout = 1): """ Executes a shell command using the scheduled tasks service""" try: buffer = b'' if timeout is None or timeout == '': timeout = 1 timeout = int(timeout) async for data, err in self.machine.tasks_cmd_exec(command, timeout): if err is not None: raise err if data is None: break try: print(data.decode()) except: print(data) return True, None #await self.machine.tasks_execute_commands([command]) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_interfaces(self): """ Lists all network interfaces of the remote machine """ try: interfaces, err = await self.machine.list_interfaces() if err is not None: raise err for iface in interfaces: print('%d: %s' % (iface['index'], iface['address'])) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_enumall(self, depth = 3): """ Enumerates all shares for all files and folders recursively """ try: depth = int(depth) async for path, otype, err in self.machine.enum_all_recursively(depth = depth): if otype is not None: print('[%s] %s' % (otype[0].upper(), path)) if err is not None: print('[E] %s %s' % (err, path)) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_printerenumdrivers(self): """ Enumerates all shares for all files and folders recursively """ try: drivers, err = await self.machine.enum_printer_drivers() if err is not None: raise err for driver in drivers: print(driver) return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_printnightmare(self, share, driverpath = ''): """ printnightmare bug using the RPRN protocol """ try: if len(driverpath) == 0: driverpath = None _, err = await self.machine.printnightmare(share, driverpath) if err is not None: raise err return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e async def do_parprintnightmare(self, share, driverpath = ''): """ printnightmare bug using the PAR protocol """ try: if len(driverpath) == 0: driverpath = None _, err = await self.machine.par_printnightmare(share, driverpath) if err is not None: raise err return True, None except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) return None, e except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) return None, e except Exception as e: traceback.print_exc() return None, e
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 SMBClient(aiocmd.PromptToolkitCmd): def __init__(self, url = None): aiocmd.PromptToolkitCmd.__init__(self, ignore_sigint=False) #Setting this to false, since True doesnt work on windows... self.conn_url = None if url is not None: self.conn_url = SMBConnectionURL(url) self.connection = None self.machine = None self.shares = {} #name -> share self.__current_share = None self.__current_directory = None async def do_login(self, url = None): """Connects to the remote machine""" try: if self.conn_url is None and url is None: print('No url was set, cant do logon') if url is not None: self.conn_url = SMBConnectionURL(url) self.connection = self.conn_url.get_connection() logger.debug(self.conn_url.get_credential()) logger.debug(self.conn_url.get_target()) await self.connection.login() self.machine = SMBMachine(self.connection) except Exception as e: traceback.print_exc() else: print('Login success') async def do_shares(self, show = True): """Lists available shares""" try: async for share, err in ef_gen(self.machine.list_shares()): if err is not None: raise err self.shares[share.name] = share if show is True: print(share.name) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_sessions(self): """Lists sessions of connected users""" try: async for sess, err in ef_gen(self.machine.list_sessions()): if err is not None: raise err print("%s : %s" % (sess.username, sess.ip_addr)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_domains(self): """Lists domain""" try: async for domain, err in self.machine.list_domains(): if err is not None: raise err print(domain) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_localgroups(self): """Lists local groups""" try: async for name, sid, err in self.machine.list_localgroups(): if err is not None: raise err print("%s : %s" % (name, sid)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_domaingroups(self, domain_name): """Lists groups in a domain""" try: async for name, sid, err in self.machine.list_groups(domain_name): if err is not None: raise err print("%s : %s" % (name, sid)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_groupmembers(self, domain_name, group_name): """Lists members of an arbitrary group""" try: async for domain, username, sid, err in self.machine.list_group_members(domain_name, group_name): if err is not None: raise err print("%s\\%s : %s" % (domain, username, sid)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_localgroupmembers(self, group_name): """Lists members of a local group""" try: async for domain, username, sid, err in self.machine.list_group_members('Builtin', group_name): if err is not None: raise err print("%s\\%s : %s" % (domain, username, sid)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_use(self, share_name): """selects share to be used""" try: if len(self.shares) == 0: await self.do_shares(show = False) if share_name not in self.shares: if share_name.upper() not in self.shares: print('Error! Uknown share name %s' % share_name) return share_name = share_name.upper() self.__current_share = self.shares[share_name] await self.__current_share.connect(self.connection) self.__current_directory = self.__current_share.subdirs[''] #this is the entry directory self.prompt = '[%s] $' % self.__current_directory.unc_path await self.do_ls(False) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_ls(self, show = True): try: if self.__current_share is None: print('No share selected!') return if self.__current_directory is None: print('No directory selected!') return #print(self.__current_directory) async for entry in self.machine.list_directory(self.__current_directory): if show == True: print(entry) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_cd(self, directory_name): try: if self.__current_share is None: print('No share selected!') return if self.__current_directory is None: print('No directory selected!') return if directory_name not in self.__current_directory.subdirs: if directory_name == '..': self.__current_directory = self.__current_directory.parent_dir self.prompt = '[%s] $' % (self.__current_directory.unc_path) return else: print('The directory "%s" is not in parent directory "%s"' % (directory_name, self.__current_directory.fullpath)) else: self.__current_directory = self.__current_directory.subdirs[directory_name] self.prompt = '[%s] $' % (self.__current_directory.unc_path) await self.do_ls(False) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() def get_current_dirs(self): if self.__current_directory is None: return [] return list(self.__current_directory.subdirs.keys()) def get_current_files(self): if self.__current_directory is None: return [] return list(self.__current_directory.files.keys()) async def do_sid(self, file_name): if file_name not in self.__current_directory.files: print('file not in current directory!') return file_obj = self.__current_directory.files[file_name] sid = await file_obj.get_security_descriptor(self.connection) print(str(sid)) async def do_dirsid(self): sid = await self.__current_directory.get_security_descriptor(self.connection) print(str(sid)) def _cd_completions(self): return SMBPathCompleter(get_current_dirs = self.get_current_dirs) def _get_completions(self): return SMBPathCompleter(get_current_dirs = self.get_current_files) async def do_services(self): """Lists remote services""" try: async for service, err in self.machine.list_services(): if err is not None: raise err print(service) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_serviceen(self, service_name): """Enables a remote service""" try: res, err = await self.machine.enable_service(service_name) if err is not None: raise err print(res) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_servicecreate(self, service_name, command, display_name = None): """Creates a remote service""" try: res, err = await self.machine.create_service(service_name, command, display_name) if err is not None: raise err except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_servicedeploy(self, path_to_exec, remote_path): """Deploys a binary file from the local system as a service on the remote system""" #servicedeploy /home/devel/Desktop/cmd.exe /shared/a.exe try: basename = ntpath.basename(remote_path) remote_path = '\\\\%s\\%s\\%s\\%s' % (self.connection.target.get_hostname_or_ip(), self.__current_share.name, self.__current_directory.fullpath , basename) await rr(self.machine.deploy_service(path_to_exec, remote_path = remote_path)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_put(self, file_name): """Uploads a file to the remote share""" try: basename = ntpath.basename(file_name) dst = '\\%s\\%s\\%s' % (self.__current_share.name, self.__current_directory.fullpath , basename) print(basename) print(dst) await self.machine.put_file(file_name, dst) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_del(self, file_name): """Removes a file from the remote share""" try: basename = ntpath.basename(file_name) dst = '\\%s\\%s\\%s' % (self.__current_share.name, self.__current_directory.fullpath , basename) print(dst) await self.machine.del_file(dst) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_regsave(self, hive_name, file_path): """Saves a registry hive to a file on remote share""" try: await rr(self.machine.save_registry_hive(hive_name, file_path)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_get(self, file_name): """Download a file from the remote share to the current folder""" try: matched = [] if file_name not in self.__current_directory.files: for fn in fnmatch.filter(list(self.__current_directory.files.keys()), file_name): matched.append(fn) if len(matched) == 0: print('File with name %s is not present in the directory %s' % (file_name, self.__current_directory.name)) return else: matched.append(file_name) for file_name in matched: file_obj = self.__current_directory.files[file_name] with tqdm.tqdm(desc = 'Downloading %s' % file_name, total=file_obj.size, unit='B', unit_scale=True, unit_divisor=1024) as pbar: with open(file_name, 'wb') as outfile: async for data in self.machine.get_file_data(file_obj): if data is None: break outfile.write(data) pbar.update(len(data)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_mkdir(self, directory_name): """Creates a directory on the remote share""" try: await self.machine.create_subdirectory(directory_name, self.__current_directory) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_dcsync(self): """It's a suprse tool that will help us later""" try: async for secret, err in self.machine.dcsync(): if err is not None: raise err print(str(secret)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc() async def do_users(self, domain = None): """List users in domain""" try: async for username, user_sid, err in self.machine.list_domain_users(domain): if err is not None: print(str(err)) print('%s %s' % (username, user_sid)) except SMBException as e: logger.debug(traceback.format_exc()) print(e.pprint()) except SMBMachineException as e: logger.debug(traceback.format_exc()) print(str(e)) except DCERPCException as e: logger.debug(traceback.format_exc()) print(str(e)) except Exception as e: traceback.print_exc()
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 amain(url, service, template, altname, onbehalf, cn = None, pfx_file = None, pfx_password = None, enroll_cert = None, enroll_password = None): try: if pfx_file is None: pfx_file = 'cert_%s.pfx' % os.urandom(4).hex() if pfx_password is None: pfx_password = '******' print('[+] Parsing connection parameters...') su = SMBConnectionURL(url) ip = su.get_target().get_hostname_or_ip() if cn is None: cn = '%s@%s' % (su.username, su.domain) print('[*] Using CN: %s' % cn) print('[+] Generating RSA privat key...') key = rsa.generate_private_key(0x10001, 2048) print('[+] Building certificate request...') attributes = { "CertificateTemplate": template, } csr = x509.CertificateSigningRequestBuilder() csr = csr.subject_name( x509.Name( [ x509.NameAttribute(NameOID.COMMON_NAME, cn), ] ) ) if altname: altname = core.UTF8String(altname).dump() csr = csr.add_extension( x509.SubjectAlternativeName( [ x509.OtherName(PRINCIPAL_NAME, altname), ] ), critical=False, ) csr = csr.sign(key, hashes.SHA256()) if onbehalf is not None: agent_key = None agent_cert = None with open(enroll_cert, 'rb') as f: agent_key, agent_cert, _ = pkcs12.load_key_and_certificates(f.read(), enroll_password) pkcs7builder = pkcs7.PKCS7SignatureBuilder().set_data(csr).add_signer(agent_key, agent_cert, hashes.SHA1()) csr = pkcs7builder.sign(Encoding.DER, options=[pkcs7.PKCS7Options.Binary]) else: csr = csr.public_bytes(Encoding.DER) print('[+] Connecting to EPM...') target, err = await EPM.create_target(ip, ICPRRPC().service_uuid, dc_ip = su.get_target().dc_ip, domain = su.get_target().domain) if err is not None: raise err print('[+] Connecting to ICRPR service...') gssapi = AuthenticatorBuilder.to_spnego_cred(su.get_credential(), target) auth = DCERPCAuth.from_smb_gssapi(gssapi) connection = DCERPC5Connection(auth, target) rpc, err = await ICPRRPC.from_rpcconnection(connection, perform_dummy=True) if err is not None: raise err logger.debug('DCE Connected!') print('[+] Requesting certificate from the service...') res, err = await rpc.request_certificate(service, csr, attributes) if err is not None: print('[-] Request failed!') raise err if res['encodedcert'] in [None, b'']: raise Exception('No certificate was returned from server!. Full message: %s' % res) print('[+] Got certificate!') cert = x509.load_der_x509_certificate(res['encodedcert']) print("[*] Cert subject: {}".format(cert.subject.rfc4514_string())) print("[*] Cert issuer: {}".format(cert.issuer.rfc4514_string())) print("[*] Cert Serial: {:X}".format(cert.serial_number)) try: ext = cert.extensions.get_extension_for_oid(ExtensionOID.EXTENDED_KEY_USAGE) for oid in ext.value: print("[*] Cert Extended Key Usage: {}".format(EKUS_NAMES.get(oid.dotted_string, oid.dotted_string))) except: print('[-] Could not verify extended key usage') try: ext = cert.extensions.get_extension_for_oid(ExtensionOID.SUBJECT_ALTERNATIVE_NAME) for name in ext.value.get_values_for_type(x509.OtherName): if name.type_id == x509.ObjectIdentifier("1.3.6.1.4.1.311.20.2.3"): print('[*] Certificate ALT NAME: %s' % core.UTF8String.load(name.value).native) break else: print('[-] Certificate doesnt have ALT NAME') except: print('[-] Certificate doesnt have ALT NAME') print('[+] Writing certificate to disk (file:"%s" pass: "******")...' % (pfx_file, pfx_password)) # Still waiting for the day oscrypto will have a pfx serializer :( # Until that we'd need to use cryptography with open(pfx_file, 'wb') as f: data = pkcs12.serialize_key_and_certificates( name=b"", key=key, cert=cert, cas=None, encryption_algorithm=BestAvailableEncryption(pfx_password.encode()) ) f.write(data) print('[+] Finished!') return True, None except Exception as e: traceback.print_exc() return False, e
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
class SMBClient(aiocmd.PromptToolkitCmd): def __init__(self, url=None): aiocmd.PromptToolkitCmd.__init__( self, ignore_sigint=False ) #Setting this to false, since True doesnt work on windows... self.conn_url = None if url is not None: self.conn_url = SMBConnectionURL(url) self.connection = None self.machine = None self.shares = {} #name -> share self.__current_share = None self.__current_directory = None async def do_login(self, url=None): try: if self.conn_url is None and url is None: print('No url was set, cant do logon') if url is not None: self.conn_url = SMBConnectionURL(url) self.connection = self.conn_url.get_connection() logger.debug(self.conn_url.get_credential()) logger.debug(self.conn_url.get_target()) await self.connection.login() self.machine = SMBMachine(self.connection) except Exception as e: traceback.print_exc() else: print('Login success') async def do_shares(self, show=True): try: async for share in self.machine.list_shares(): self.shares[share.name] = share if show is True: print(share.name) except Exception as e: traceback.print_exc() async def do_sessions(self): try: async for sess in self.machine.list_sessions(): print("%s : %s" % (sess.username, sess.ip_addr)) except Exception as e: traceback.print_exc() async def do_domains(self): try: async for domain in self.machine.list_domains(): print(domain) except Exception as e: traceback.print_exc() async def do_localgroups(self): try: async for name, sid in self.machine.list_localgroups(): print("%s : %s" % (name, sid)) except Exception as e: traceback.print_exc() async def do_domaingroups(self, domain_name): try: async for name, sid in self.machine.list_groups(domain_name): print("%s : %s" % (name, sid)) except Exception as e: traceback.print_exc() async def do_groupmembers(self, domain_name, group_name): try: async for domain, username, sid in self.machine.list_group_members( domain_name, group_name): print("%s\\%s : %s" % (domain, username, sid)) except Exception as e: traceback.print_exc() async def do_localgroupmembers(self, group_name): try: async for domain, username, sid in self.machine.list_group_members( 'Builtin', group_name): print("%s\\%s : %s" % (domain, username, sid)) except Exception as e: traceback.print_exc() async def do_use(self, share_name): try: if len(self.shares) == 0: await self.do_shares(show=False) if share_name in self.shares: self.__current_share = self.shares[share_name] await self.__current_share.connect(self.connection) self.__current_directory = self.__current_share.subdirs[ ''] #this is the entry directory else: print('Error! Uknown share name %s' % share_name) except Exception as e: traceback.print_exc() async def do_ls(self): try: if self.__current_share is None: print('No share selected!') return if self.__current_directory is None: print('No directory selected!') return print(self.__current_directory) async for entry in self.machine.list_directory( self.__current_directory): print(entry) except Exception as e: traceback.print_exc() async def do_cd(self, directory_name): try: if self.__current_share is None: print('No share selected!') return if self.__current_directory is None: print('No directory selected!') return if directory_name not in self.__current_directory.subdirs: print('The directory "%s" is not in parent directory "%s"' % (directory_name, self.__current_directory.fullpath)) else: self.__current_directory = self.__current_directory.subdirs[ directory_name] except Exception as e: traceback.print_exc() async def do_services(self): try: async for service in self.machine.list_services(): print(service) except Exception as e: traceback.print_exc() async def do_put(self, file_name): try: basename = ntpath.basename(file_name) dst = '\\\\%s\\%s\\%s\\%s' % ( self.connection.target.get_hostname_or_ip(), self.__current_share.name, self.__current_directory.fullpath, basename) print(basename) print(dst) await self.machine.put_file_raw(file_name, dst) except Exception as e: traceback.print_exc() async def do_get(self, file_name): try: if file_name not in self.__current_directory.files: print('File with name %s is not present in the directory %s' % (file_name, self.__current_directory.name)) return out_path = file_name await self.machine.get_file( out_path, self.__current_directory.files[file_name]) except Exception as e: traceback.print_exc() async def do_mkdir(self, directory_name): try: await self.machine.create_subdirectory(directory_name, self.__current_directory) except Exception as e: traceback.print_exc() async def do_dcsync(self): try: async for secret in self.machine.dcsync(): print(str(secret)) except Exception as e: traceback.print_exc()