def _set_plugins(): # TODO # load plugin scripts .pyc file support if conf.plugins: founds = [] cache_plugins = copy.deepcopy(conf.plugins) for found in glob.glob( os.path.join(paths.POCSUITE_PLUGINS_PATH, "*.py*")): dirname, filename = os.path.split(found) plugin_name = os.path.splitext(filename)[0] if found.endswith(('__init__.py', '__init__.pyc')): continue if plugin_name not in conf.plugins: continue cache_plugins.remove(plugin_name) founds.append(found) if len(cache_plugins) > 0: for file in cache_plugins: if os.path.exists(file): founds.append(file) for file in founds: debug_msg = "loading plugin script '{0}'".format(file) logger.debug(debug_msg) load_file_to_module(file)
def _set_conf_attributes(): """ This function set some needed attributes into the configuration singleton. """ debug_msg = "initializing the configuration" logger.debug(debug_msg) conf.url = None conf.url_file = None conf.mode = 'verify' conf.poc = None conf.cookie = None conf.host = None conf.referer = None conf.agent = None conf.headers = None conf.random_agent = None conf.proxy = None conf.proxy_cred = None conf.proxies = {} conf.timeout = 30 conf.retry = 0 conf.delay = 0 conf.http_headers = {} conf.login_user = None conf.login_pass = None conf.shodan_token = None conf.censys_uid = None conf.censys_secret = None conf.dork = None conf.dork_zoomeye = None conf.dork_shodan = None conf.dork_censys = None conf.max_page = 1 conf.search_type = 'host' conf.comparison = False conf.vul_keyword = None conf.ssvid = None conf.plugins = [] conf.threads = 1 conf.batch = False conf.check_requires = False conf.quiet = False conf.update_all = False conf.verbose = 1 conf.ipv6 = False conf.multiple_targets = False conf.pocs_path = None conf.output_path = None conf.plugin_name = None conf.plugin_code = None conf.connect_back_host = None conf.connect_back_port = DEFAULT_LISTENER_PORT conf.console_mode = False conf.show_version = False conf.api = False # api for zipoc conf.ppt = False
def update(): if not conf.update_all: return success = False if not os.path.exists(os.path.join(paths.POCSUITE_ROOT_PATH, "../", ".git")): warn_msg = "not a git repository. It is recommended to clone the 'knownsec/pocsuite3' repository " warn_msg += "from GitHub (e.g. 'git clone --depth 1 {} pocsuite3')".format( GIT_REPOSITORY) logger.warn(warn_msg) if VERSION == get_latest_revision(): logger.info("already at the latest revision '{}'".format( get_revision_number())) return else: info_msg = "updating pocsuite3 to the latest development revision from the " info_msg += "GitHub repository" logger.info(info_msg) debug_msg = "pocsuite3 will try to update itself using 'git' command" logger.debug(debug_msg) data_to_stdout("\r[{0}] [INFO] update in progress ".format( time.strftime("%X"))) cwd_path = os.path.join(paths.POCSUITE_ROOT_PATH, "../") try: process = subprocess.Popen( "git checkout . && git pull %s HEAD" % GIT_REPOSITORY, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd_path.encode(sys.getfilesystemencoding() or UNICODE_ENCODING)) poll_process(process, True) stdout, stderr = process.communicate() success = not process.returncode except (IOError, OSError) as ex: success = False stderr = str(ex) if success: logger.info("{0} the latest revision '{1}'".format( "already at" if b"Already" in stdout else "updated to", get_revision_number())) else: if "Not a git repository" in stderr: err_msg = "not a valid git repository. Please checkout the 'knownsec/pocsuite3' repository " err_msg += "from GitHub (e.g. 'git clone --depth 1 %s pocsuite3')" % GIT_REPOSITORY logger.error(err_msg) else: logger.error("update could not be completed ('%s')" % re.sub(r"\W+", " ", stderr).strip()) if not success: if IS_WIN: info_msg = "for Windows platform it's recommended " info_msg += "to use a GitHub for Windows client for updating " info_msg += "purposes (http://windows.github.com/) or just " info_msg += "download the latest snapshot from " info_msg += "https://github.com/knownsec/pocsuite3/downloads" else: info_msg = "for Linux platform it's recommended " info_msg += "to install a standard 'git' package (e.g.: 'sudo apt-get install git')" logger.info(info_msg)
def get_links(self, url, url_ext=()): # TODO: # set base url from base tag or current url self.base_url = url url_part = urlparse(url) self.origin = (url_part.scheme, url_part.netloc) self.urls = { 'url': set(), 'js': set(), 'img': set() } if isinstance(url_ext, str): url_ext = set(url_ext) self.url_ext = url_ext debug_msg = "crawler visiting: {0}".format(url) logger.debug(debug_msg) resp = requests.get(url) content_type = resp.headers.get('content-type', '') if 'text/html' in content_type: html = resp.text self.feed(html) return self.urls
def _set_network_proxy(): if conf.proxy: debug_msg = "setting the HTTP/SOCKS proxy for all network requests" logger.debug(debug_msg) try: _ = urlsplit(conf.proxy) except Exception as ex: err_msg = "invalid proxy address '{0}' ('{1}')".format( conf.proxy, str(ex)) raise PocsuiteSyntaxException(err_msg) hostname_port = _.netloc.split(":") scheme = _.scheme.upper() hostname = hostname_port[0] port = None username = None password = None if len(hostname_port) == 2: try: port = int(hostname_port[1]) except Exception: pass if not all((scheme, hasattr(PROXY_TYPE, scheme), hostname, port)): err_msg = "proxy value must be in format '({0})://address:port'".format( "|".join(_[0].lower() for _ in get_public_type_members(PROXY_TYPE))) raise PocsuiteSyntaxException(err_msg) if conf.proxy_cred: _ = re.search(r"\A(.*?):(.*?)\Z", conf.proxy_cred) if not _: err_msg = "proxy authentication credentials " err_msg += "value must be in format username:password" raise PocsuiteSyntaxException(err_msg) else: username = _.group(1) password = _.group(2) if scheme in (PROXY_TYPE.SOCKS4, PROXY_TYPE.SOCKS5): socks.set_default_proxy( socks.PROXY_TYPE_SOCKS5 if scheme == PROXY_TYPE.SOCKS5 else socks.PROXY_TYPE_SOCKS4, hostname, port, username=username, password=password) socket.socket = socks.socksocket else: if conf.proxy_cred: proxy_string = "{0}@".format(conf.proxy_cred) else: proxy_string = "" proxy_string = "{0}{1}:{2}".format(proxy_string, hostname, port) conf.proxies = {"http": proxy_string, "https": proxy_string}
def config_file_parser(configFile): """ Parse configuration file and save settings into the configuration advanced dictionary. """ # global config debugMsg = "parsing configuration file" logger.debug(debugMsg) if not os.path.isfile(configFile): raise PocsuiteFilePathException( "file '{}' don't exist".format(configFile)) config = ConfigParser() config.read(configFile) if not config.has_section("Target"): errMsg = "missing a mandatory section 'Target' in the configuration file" raise PocsuiteMissingMandatoryOptionException(errMsg) sections = config.sections() for section in sections: options = config.options(section) if options: for option in options: datatype = "string" try: datatype = optDict[section][option] except KeyError: pass try: if datatype == OPTION_TYPE.BOOLEAN: value = config.getboolean( section, option) if config.get(section, option) else False elif datatype == OPTION_TYPE.INTEGER: value = config.getint(section, option) if config.get( section, option) else 0 elif datatype == OPTION_TYPE.FLOAT: value = config.getfloat(section, option) if config.get( section, option) else 0.0 else: value = config.get(section, option) except ValueError as ex: errMsg = "error occurred while processing the option " errMsg += "'%s' in provided configuration file ('%s')" % ( option, ex) raise PocsuiteValueException(errMsg) if value: conf[option] = value
def _set_plugins(): # TODO # load plugin scripts .pyc file support if conf.plugins: for found in glob.glob(os.path.join(paths.POCSUITE_PLUGINS_PATH, "*.py*")): dirname, filename = os.path.split(found) plugin_name = os.path.splitext(filename)[0] if found.endswith(('__init__.py', '__init__.pyc')): continue if plugin_name not in conf.plugins: continue debug_msg = "loading plugin script '{0}'".format(found) logger.debug(debug_msg) load_file_to_module(found)
def execute(self, target, headers=None, params=None, mode='verify', verbose=True): self.target = target self.url = parse_target_url(target) if self.current_protocol == POC_CATEGORY.PROTOCOL.HTTP else self.build_url() self.headers = headers self.params = str_to_dict(params) if params else {} self.mode = mode self.verbose = verbose self.expt = (0, 'None') # TODO output = None try: output = self._execute() except NotImplementedError as e: self.expt = (ERROR_TYPE_ID.NOTIMPLEMENTEDERROR, e) logger.log(CUSTOM_LOGGING.ERROR, 'POC: {0} not defined "{1}" mode'.format(self.name, self.mode)) output = Output(self) except ConnectTimeout as e: self.expt = (ERROR_TYPE_ID.CONNECTTIMEOUT, e) while conf.retry > 0: logger.debug('POC: {0} timeout, start it over.'.format(self.name)) try: output = self._execute() break except ConnectTimeout: logger.debug('POC: {0} time-out retry failed!'.format(self.name)) conf.retry -= 1 else: msg = "connect target '{0}' failed!".format(target) logger.error(msg) output = Output(self) except HTTPError as e: self.expt = (ERROR_TYPE_ID.HTTPERROR, e) logger.warn('POC: {0} HTTPError occurs, start it over.'.format(self.name)) output = Output(self) except ConnectionError as e: self.expt = (ERROR_TYPE_ID.CONNECTIONERROR, e) msg = "connect target '{0}' failed!".format(target) logger.error(msg) output = Output(self) except TooManyRedirects as e: self.expt = (ERROR_TYPE_ID.TOOMANYREDIRECTS, e) logger.debug(str(e)) output = Output(self) except Exception as e: self.expt = (ERROR_TYPE_ID.OTHER, e) logger.debug(str(e)) output = Output(self) return output
def _set_kb_attributes(flush_all=True): """ This function set some needed attributes into the knowledge base singleton. """ debug_msg = "initializing the knowledge base" logger.debug(debug_msg) kb.abs_file_paths = set() kb.os = None kb.os_version = None kb.arch = None kb.dbms = None kb.auth_header = None kb.counters = {} kb.multi_thread_mode = False kb.thread_continue = True kb.thread_exception = False kb.word_lists = None kb.single_log_flags = set() kb.cache = AttribDict() kb.cache.addrinfo = {} kb.cache.content = {} kb.cache.regex = {} kb.data = AttribDict() kb.data.local_ips = [] kb.data.connect_back_ip = None kb.data.connect_back_port = DEFAULT_LISTENER_PORT kb.data.clients = [] kb.targets = OrderedSet() kb.plugins = AttribDict() kb.plugins.targets = AttribDict() kb.plugins.pocs = AttribDict() kb.plugins.results = AttribDict() kb.results = [] kb.current_poc = None kb.registered_pocs = AttribDict() kb.task_queue = Queue() kb.cmd_line = DIY_OPTIONS or [] kb.comparison = None
def create_shellcode(self, _shellcode_type='reverse', command='calc.exe', message='', encode=None, make_exe=0, debug=0, filename="", dll_inj_funcs=[], shell_args={}, use_precompiled=True): """ Function for create shellcode. :param _shellcode_type: (string) Can be "reverse" or "bind". :param command: (string) Command for Windows command-shellcode. :param message: (string) Message for "message" for message-shellcode. :param encode: (string) Encoder type. Can be "xor", "alphanum", "rot_13", "fnstenv" or "jumpcall". If empty shellcode will not be encoded. :param make_exe: (bool) or (int) If True(or 1) exe file will be generated from shellcode. :param debug: (bool) or (int) If True(or 1) shellcode will be printed to stdout. :param filename: (string) Used for assign special name to executable or dll shellcode. :param dll_inj_funcs: (list of strings) Functions names for dll hijacking. If not empty dll with shellcode will be generated. :param cloud_generate (bool) Used for generate shellcode on cloud server. :return: (string) Generated shellcode. """ generator = ShellGenerator(self.OS_TARGET, self.OS_TARGET_ARCH) shellcode, self.binary_path = generator.get_shellcode( _shellcode_type, connectback_ip=self.CONNECTBACK_IP, connectback_port=self.CONNECTBACK_PORT, make_exe=make_exe, debug=debug, filename=filename, dll_inj_funcs=dll_inj_funcs, shell_args=shell_args, use_precompiled=use_precompiled) if encode: if debug: logger.debug("[] Encode shellcode is on and started") e = CodeEncoders(self.OS_SYSTEM, self.OS_TARGET, self.OS_TARGET_ARCH, self.BADCHARS) e_shellcode = e.encode_shellcode(shellcode, encode, debug) if debug: logger.debug("Length of encoded shellcode: %d" % len(e_shellcode)) logger.debug("[] Encode shellcode finished") if e_shellcode: shellcode = e_shellcode else: if debug: logger.debug("[] Encode shellcode is off") return shellcode
def start(): tasks_count = kb.task_queue.qsize() info_msg = "pocsusite got a total of {0} tasks".format(tasks_count) logger.info(info_msg) logger.debug("pocsuite will open {} threads".format(conf.threads)) try: run_threads(conf.threads, task_run) finally: task_done() if conf.mode == "shell" and not conf.api: info_msg = "connect back ip: {0} port: {1}".format(conf.connect_back_host, conf.connect_back_port) logger.info(info_msg) info_msg = "waiting for shell connect to pocsuite" logger.info(info_msg) if conf.console_mode: handle_listener_connection_for_console() else: handle_listener_connection()
def get_shellcode(self, shellcode_type, connectback_ip="127.0.0.1", connectback_port=5555, make_exe=0, debug=0, filename="", dll_inj_funcs=None, shell_args=None, use_precompiled=True): if shell_args is None: shell_args = {} if dll_inj_funcs is None: dll_inj_funcs = [] self.check_settings(connectback_ip, connectback_port) filepath = '' if self.use_precompiled: logger.info( 'Some utils needed for shellcode compilation are not found. Only precompiled shellcodes can be used.' ) self.use_precompiled = use_precompiled or self.use_precompiled ext = '.bin' if self.use_precompiled else '.asm' if shellcode_type == SHELLCODE_CONNECTION.BIND: path = self._make_path('bind_tcp' + ext) if self.use_precompiled: values = dict(BIND_PORT=port_to_hex(connectback_port)) else: values = dict(BIND_PORT=port_to_dd(connectback_port)) elif shellcode_type == SHELLCODE_CONNECTION.REVERSE: path = self._make_path('reverse_tcp' + ext) if self.use_precompiled: values = dict(CONNECTBACK_IP=ip_to_hex(connectback_ip), CONNECTBACK_PORT=port_to_hex(connectback_port)) else: values = dict(CONNECTBACK_IP=ip_to_dd(connectback_ip), CONNECTBACK_PORT=port_to_dd(connectback_port)) # handle custom shellcode else: path = os.path.join(self.shellcodes_root, shellcode_type + ext) values = shell_args shell = self.read_and_replace(path, values, use_precompiled) if not self.use_precompiled: shell, filepath = create_shellcode(shell, self.OS_TARGET, self.OS_TARGET_ARCH, make_exe, debug=debug, filename=filename, dll_inj_funcs=dll_inj_funcs) if debug: logger.debug('Shellcode generated with length=%s' % len(shell)) logger.debug(b''.join(b'\\x%02x' % x for x in shell)) if (make_exe or dll_inj_funcs) and self.use_precompiled: exe_gen = ShellcodeToExe(shell, self.OS_TARGET, self.OS_TARGET_ARCH, filename=filename, dll_inj_funcs=dll_inj_funcs) if make_exe: filepath = exe_gen.create_executable() if debug: logger.debug('Executable trojan is generated: %s' % filepath) if dll_inj_funcs: filepath = exe_gen.create_executable() if debug: logger.debug('DLL is generated: %s' % filepath + '.dll') return shell, filepath
import readline as _readline except ImportError: try: from pyreadline import * import pyreadline as _readline except ImportError: # raise PocsuiteSystemException("Import pyreadline faild,try pip3 install pyreadline") pass if IS_WIN and _readline: try: _outputfile = _readline.GetOutputFile() except AttributeError: debugMsg = "Failed GetOutputFile when using platform's " debugMsg += "readline library" logger.debug(debugMsg) _readline = None # Test to see if libedit is being used instead of GNU readline. # Thanks to Boyd Waters for this patch. uses_libedit = False if PLATFORM == 'mac' and _readline: import commands (status, result) = commands.getstatusoutput("otool -L %s | grep libedit" % _readline.__file__) if status == 0 and len(result) > 0: # We are bound to libedit - new in Leopard
def cmd_line_parser(argv=None): """ This function parses the command line parameters and arguments """ if not argv: argv = sys.argv _ = os.path.basename(argv[0]) usage = "pocsuite [options]" parser = OptionParser(usage=usage) try: parser.add_option("--version", dest="show_version", action="store_true", help="Show program's version number and exit") parser.add_option("--update", dest="update_all", action="store_true", help="Update Pocsuite") parser.add_option("-v", dest="verbose", type="int", default=1, help="Verbosity level: 0-6 (default 1)") # Target options target = OptionGroup( parser, "Target", "At least one of these " "options has to be provided to define the target(s)") target.add_option( "-u", "--url", dest="url", help="Target URL (e.g. \"http://www.site.com/vuln.php?id=1\")") target.add_option("-f", "--file", dest="url_file", help="Scan multiple targets given in a textual file") target.add_option( "-r", dest="poc", help="Load POC file from local or remote from seebug website") # Mode options mode = OptionGroup(parser, "Mode", "Pocsuite running mode options") mode.add_option("--verify", dest="mode", default='verify', action="store_const", const='verify', help="Run poc with verify mode") mode.add_option("--attack", dest="mode", action="store_const", const='attack', help="Run poc with attack mode") mode.add_option("--shell", dest="mode", action="store_const", const='shell', help="Run poc with shell mode") # Requests options request = OptionGroup(parser, "Request", "Network request options") request.add_option("--cookie", dest="cookie", help="HTTP Cookie header value") request.add_option("--host", dest="host", help="HTTP Host header value") request.add_option("--referer", dest="referer", help="HTTP Referer header value") request.add_option("--user-agent", dest="agent", help="HTTP User-Agent header value") request.add_option( "--random-agent", dest="random_agent", action="store_true", default=False, help="Use randomly selected HTTP User-Agent header value") request.add_option("--proxy", dest="proxy", help="Use a proxy to connect to the target URL") request.add_option( "--proxy-cred", dest="proxy_cred", help="Proxy authentication credentials (name:password)") request.add_option( "--timeout", dest="timeout", help="Seconds to wait before timeout connection (default 30)") request.add_option("--retry", dest="retry", default=False, help="Time out retrials times.") request.add_option("--delay", dest="delay", help="Delay between two request of one thread") request.add_option( "--headers", dest="headers", help="Extra headers (e.g. \"key1: value1\\nkey2: value2\")") # Account options account = OptionGroup(parser, "Account", "Telnet404 account options") account.add_option("--login-user", dest="login_user", help="Telnet404 login user") account.add_option("--login-pass", dest="login_pass", help="Telnet404 login password") # Modules options modules = OptionGroup(parser, "Modules", "Modules(Seebug Zoomeye CEye Listener) options") modules.add_option("--dork", dest="dork", action="store", default=None, help="Zoomeye dork used for search.") modules.add_option( "--max-page", dest="max_page", type=int, default=1, help="Max page used in ZoomEye API(10 targets/Page).") modules.add_option("--search-type", dest="search_type", action="store", default='host', help="search type used in ZoomEye API, web or host") modules.add_option("--vul-keyword", dest="vul_keyword", action="store", default=None, help="Seebug keyword used for search.") modules.add_option("--ssv-id", dest="ssvid", action="store", default=None, help="Seebug SSVID number for target PoC.") modules.add_option( "--lhost", dest="connect_back_host", action="store", default=None, help="Connect back host for target PoC in shell mode") modules.add_option( "--lport", dest="connect_back_port", action="store", default=None, help="Connect back port for target PoC in shell mode") # Optimization options optimization = OptionGroup(parser, "Optimization", "Optimization options") optimization.add_option("--plugins", dest="plugins", action="store", default=None, help="Load plugins to execute") optimization.add_option("--pocs-path", dest="pocs_path", action="store", default=None, help="User defined poc scripts path") optimization.add_option( "--threads", dest="threads", type=int, default=1, help="Max number of concurrent network requests (default 1)") optimization.add_option( "--batch", dest="batch", help="Automatically choose defaut choice without asking.") optimization.add_option("--requires", dest="check_requires", action="store_true", default=False, help="Check install_requires") optimization.add_option( "--quiet", dest="quiet", action="store_true", default=False, help="Activate quiet mode, working without logger.") # Diy options diy_options = OptionGroup(parser, "Poc options", "definition options for PoC") for line in argv: if line.startswith("--"): if line[2:] not in CMD_PARSE_WHITELIST: diy_options.add_option(line) parser.add_option_group(target) parser.add_option_group(mode) parser.add_option_group(request) parser.add_option_group(account) parser.add_option_group(modules) parser.add_option_group(optimization) parser.add_option_group(diy_options) (args, _) = parser.parse_args(argv) if not any((args.url, args.url_file, args.update_all, args.plugins, args.dork)): err_msg = "missing a mandatory option (-u, --url-file, --update). " err_msg += "Use -h for basic and -hh for advanced help\n" parser.error(err_msg) return args except (OptionError, TypeError) as e: parser.error(e) except SystemExit: # Protection against Windows dummy double clicking if IS_WIN: data_to_stdout("\nPress Enter to continue...") input() raise debug_msg = "parsing command line" logger.debug(debug_msg)