def main(): parser = argparse.ArgumentParser(description='King Phisher TOTP Enrollment Utility', conflict_handler='resolve') utilities.argp_add_args(parser) config_group = parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-c', '--config', dest='server_config', type=argparse.FileType('r'), help='the server configuration file') config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url') parser.add_argument('--otp', dest='otp_secret', help='a specific otp secret') parser.add_argument('user', help='the user to mange') parser.add_argument('action', choices=('remove', 'set', 'show'), help='the action to preform') parser.epilog = PARSER_EPILOG arguments = parser.parse_args() utilities.configure_stream_logger(arguments.loglvl, arguments.logger) if arguments.database_url: database_connection_url = arguments.database_url elif arguments.server_config: server_config = yaml.load(arguments.server_config) database_connection_url = server_config['server']['database'] else: raise RuntimeError('no database connection was specified') manager.init_database(database_connection_url) session = manager.Session() user = session.query(models.User).filter_by(id=arguments.user).first() if not user: color.print_error("invalid user id: {0}".format(arguments.user)) return for case in utilities.switch(arguments.action): if case('remove'): user.otp_secret = None break if case('set'): if user.otp_secret: color.print_error("the specified user already has an otp secret set") return if arguments.otp_secret: new_otp = arguments.otp_secret else: new_otp = pyotp.random_base32() if len(new_otp) != 16: color.print_error("invalid otp secret length, must be 16") return user.otp_secret = new_otp break if user.otp_secret: color.print_status("user: {0} otp: {1}".format(user.id, user.otp_secret)) totp = pyotp.TOTP(user.otp_secret) uri = totp.provisioning_uri(user.id + '@king-phisher') + '&issuer=King%20Phisher' color.print_status("provisioning uri: {0}".format(uri)) else: color.print_status("user: {0} otp: N/A".format(user.id)) session.commit()
def test_get_meta_data(self): try: db_manager.init_database('sqlite://') except Exception as error: self.fail("failed to initialize the database (error: {0})".format( error.__class__.__name__)) database_driver = db_manager.get_meta_data('database_driver') self.assertEqual(database_driver, 'sqlite') schema_version = db_manager.get_meta_data('schema_version') self.assertEqual(schema_version, db_models.SCHEMA_VERSION)
def _init_db(self): try: db_manager.init_database('sqlite://') except Exception as error: self.fail("failed to initialize the database (error: {0})".format(error.__class__.__name__)) alice = db_models.User(id='alice', otp_secret='secret') calie = db_models.User(id='calie', otp_secret='secret') session = db_manager.Session() session.add(alice) session.add(calie) session.commit() session.close()
def main(): parser = argparse.ArgumentParser(description='King Phisher Interactive Database Console', conflict_handler='resolve') utilities.argp_add_args(parser) config_group = parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-c', '--config', dest='server_config', help='the server configuration file') config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url') arguments = parser.parse_args() if arguments.database_url: database_connection_url = arguments.database_url elif arguments.server_config: server_config = configuration.ex_load_config(arguments.server_config) database_connection_url = server_config.get('server.database') else: raise RuntimeError('no database connection was specified') engine = manager.init_database(database_connection_url) session = manager.Session() rpc_session = aaa.AuthenticatedSession(user=getpass.getuser()) console = code.InteractiveConsole(dict( engine=engine, graphql_query=graphql_query, manager=manager, models=models, pprint=pprint.pprint, rpc_session=rpc_session, session=session )) console.interact('starting interactive database console') if os.path.isdir(os.path.dirname(history_file)): readline.write_history_file(history_file)
def test_set_meta_data(self): try: db_manager.init_database('sqlite://') except Exception as error: self.fail("failed to initialize the database (error: {0})".format(error.__class__.__name__)) # set a new value key = random_string(10) value = random_string(20) db_manager.set_meta_data(key, value) self.assertEqual(db_manager.get_meta_data(key), value) # update an existing value value = random_string(30) db_manager.set_meta_data(key, value) self.assertEqual(db_manager.get_meta_data(key), value)
def main(): parser = argparse.ArgumentParser(description='King Phisher Interactive Database Console', conflict_handler='resolve') parser.add_argument('-v', '--version', action='version', version=parser.prog + ' Version: ' + version.version) parser.add_argument('-L', '--log', dest='loglvl', action='store', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], default='CRITICAL', help='set the logging level') config_group = parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-c', '--config', dest='server_config', type=argparse.FileType('r'), help='the server configuration file') config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url') arguments = parser.parse_args() logging.getLogger('').setLevel(logging.DEBUG) console_log_handler = logging.StreamHandler() console_log_handler.setLevel(getattr(logging, arguments.loglvl)) console_log_handler.setFormatter(logging.Formatter("%(levelname)-8s %(message)s")) logging.getLogger('').addHandler(console_log_handler) if arguments.database_url: database_connection_url = arguments.database_url elif arguments.server_config: server_config = yaml.load(arguments.server_config) database_connection_url = server_config['server']['database'] else: raise RuntimeError('no database connection was specified') engine = manager.init_database(database_connection_url) session = manager.Session() console = code.InteractiveConsole(dict(engine=engine, manager=manager, models=models, session=session)) console.interact('starting interactive database console')
def main(): parser = argparse.ArgumentParser(description='King Phisher Interactive Database Console', conflict_handler='resolve') utilities.argp_add_args(parser) config_group = parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-c', '--config', dest='server_config', type=argparse.FileType('r'), help='the server configuration file') config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url') arguments = parser.parse_args() if arguments.database_url: database_connection_url = arguments.database_url elif arguments.server_config: server_config = yaml.load(arguments.server_config) database_connection_url = server_config['server']['database'] else: raise RuntimeError('no database connection was specified') engine = manager.init_database(database_connection_url) session = manager.Session() rpc_session = aaa.AuthenticatedSession(user=getpass.getuser()) console = code.InteractiveConsole(dict( engine=engine, graphql=graphql, graphql_query=graphql_query, manager=manager, models=models, pprint=pprint.pprint, rpc_session=rpc_session, session=session )) console.interact('starting interactive database console') if os.path.isdir(os.path.dirname(history_file)): readline.write_history_file(history_file)
def test_set_meta_data(self): try: db_manager.init_database('sqlite://') except Exception as error: self.fail("failed to initialize the database (error: {0})".format( error.__class__.__name__)) # set a new value key = random_string(10) value = random_string(20) db_manager.set_meta_data(key, value) self.assertEqual(db_manager.get_meta_data(key), value) # update an existing value value = random_string(30) db_manager.set_meta_data(key, value) self.assertEqual(db_manager.get_meta_data(key), value)
def __init__(self, config, HandlerClass, *args, **kwargs): """ :param config: Configuration to retrieve settings from. :type config: :py:class:`smoke_zephyr.configuration.Configuration` """ # additional mime types to be treated as html because they're probably cloned pages HandlerClass.extensions_map.update({ '': 'text/html', '.asp': 'text/html', '.aspx': 'text/html', '.cfm': 'text/html', '.cgi': 'text/html', '.do': 'text/html', '.jsp': 'text/html', '.nsf': 'text/html', '.php': 'text/html', '.srf': 'text/html' }) super(KingPhisherServer, self).__init__(HandlerClass, *args, **kwargs) self.logger = logging.getLogger('KingPhisher.Server') self.config = config """A :py:class:`~smoke_zephyr.configuration.Configuration` instance used as the main King Phisher server configuration.""" self.serve_files = True self.serve_files_root = config.get('server.web_root') self.serve_files_list_directories = False self.serve_robots_txt = True self.database_engine = db_manager.init_database( config.get('server.database')) self.http_server.config = config self.http_server.throttle_semaphore = threading.Semaphore() self.http_server.session_manager = aaa.AuthenticatedSessionManager( timeout=config.get_if_exists('server.authentication.cache_timeout', '30m')) self.http_server.forked_authenticator = aaa.ForkedAuthenticator( cache_timeout=config.get_if_exists( 'server.authentication.cache_timeout', '10m'), required_group=config.get_if_exists('server.authentication.group'), pam_service=config.get_if_exists( 'server.authentication.pam_service', 'sshd')) self.job_manager = job.JobManager() """A :py:class:`~smoke_zephyr.job.JobManager` instance for scheduling tasks.""" self.job_manager.start() self.http_server.job_manager = self.job_manager loader = jinja2.FileSystemLoader(config.get('server.web_root')) global_vars = {} if config.has_section('server.page_variables'): global_vars = config.get('server.page_variables') global_vars['embed_youtube_video'] = pages.embed_youtube_video global_vars['make_csrf_page'] = pages.make_csrf_page global_vars['make_redirect_page'] = pages.make_redirect_page self.http_server.template_env = templates.TemplateEnvironmentBase( loader=loader, global_vars=global_vars) self.__geoip_db = geoip.init_database( config.get('server.geoip.database')) self.__is_shutdown = threading.Event() self.__is_shutdown.clear()
def __init__(self, config, HandlerClass, *args, **kwargs): """ :param config: Configuration to retrieve settings from. :type config: :py:class:`smoke_zephyr.configuration.Configuration` """ # additional mime types to be treated as html because they're probably cloned pages HandlerClass.extensions_map.update( { "": "text/html", ".asp": "text/html", ".aspx": "text/html", ".cfm": "text/html", ".cgi": "text/html", ".do": "text/html", ".jsp": "text/html", ".nsf": "text/html", ".php": "text/html", ".srf": "text/html", } ) super(KingPhisherServer, self).__init__(HandlerClass, *args, **kwargs) self.logger = logging.getLogger("KingPhisher.Server") self.config = config """A :py:class:`~smoke_zephyr.configuration.Configuration` instance used as the main King Phisher server configuration.""" self.serve_files = True self.serve_files_root = config.get("server.web_root") self.serve_files_list_directories = False self.serve_robots_txt = True self.database_engine = db_manager.init_database(config.get("server.database")) self.http_server.config = config self.http_server.throttle_semaphore = threading.Semaphore() self.http_server.session_manager = aaa.AuthenticatedSessionManager( timeout=config.get_if_exists("server.authentication.cache_timeout", "30m") ) self.http_server.forked_authenticator = aaa.ForkedAuthenticator( cache_timeout=config.get_if_exists("server.authentication.cache_timeout", "10m"), required_group=config.get_if_exists("server.authentication.group"), pam_service=config.get_if_exists("server.authentication.pam_service", "sshd"), ) self.job_manager = job.JobManager() """A :py:class:`~smoke_zephyr.job.JobManager` instance for scheduling tasks.""" self.job_manager.start() self.http_server.job_manager = self.job_manager loader = jinja2.FileSystemLoader(config.get("server.web_root")) global_vars = {} if config.has_section("server.page_variables"): global_vars = config.get("server.page_variables") global_vars["embed_youtube_video"] = pages.embed_youtube_video global_vars["make_csrf_page"] = pages.make_csrf_page global_vars["make_redirect_page"] = pages.make_redirect_page self.http_server.template_env = templates.TemplateEnvironmentBase(loader=loader, global_vars=global_vars) self.__geoip_db = geoip.init_database(config.get("server.geoip.database")) self.__is_shutdown = threading.Event() self.__is_shutdown.clear()
def __init__(self, config, HandlerClass, *args, **kwargs): """ :param config: Configuration to retrieve settings from. :type config: :py:class:`smoke_zephyr.configuration.Configuration` """ # additional mime types to be treated as html because they're probably cloned pages HandlerClass.extensions_map.update({ '': 'text/html', '.asp': 'text/html', '.aspx': 'text/html', '.cfm': 'text/html', '.cgi': 'text/html', '.do': 'text/html', '.jsp': 'text/html', '.nsf': 'text/html', '.php': 'text/html', '.srf': 'text/html' }) super(KingPhisherServer, self).__init__(HandlerClass, *args, **kwargs) self.logger = logging.getLogger('KingPhisher.Server') self.config = config """A :py:class:`~smoke_zephyr.configuration.Configuration` instance used as the main King Phisher server configuration.""" self.serve_files = True self.serve_files_root = config.get('server.web_root') self.serve_files_list_directories = False self.serve_robots_txt = True self.database_engine = db_manager.init_database(config.get('server.database')) self.http_server.config = config self.http_server.throttle_semaphore = threading.Semaphore() self.http_server.session_manager = aaa.AuthenticatedSessionManager() self.http_server.forked_authenticator = aaa.ForkedAuthenticator(required_group=config.get_if_exists('server.authentication.group')) self.logger.debug('forked an authenticating process with PID: ' + str(self.http_server.forked_authenticator.child_pid)) self.job_manager = job.JobManager() """A :py:class:`~smoke_zephyr.job.JobManager` instance for scheduling tasks.""" self.job_manager.start() self.http_server.job_manager = self.job_manager loader = jinja2.FileSystemLoader(config.get('server.web_root')) global_vars = {} if config.has_section('server.page_variables'): global_vars = config.get('server.page_variables') global_vars['embed_youtube_video'] = pages.embed_youtube_video global_vars['make_csrf_page'] = pages.make_csrf_page global_vars['make_redirect_page'] = pages.make_redirect_page self.http_server.template_env = templates.BaseTemplateEnvironment(loader=loader, global_vars=global_vars) self.__geoip_db = geoip.init_database(config.get('server.geoip.database')) self.__is_shutdown = threading.Event() self.__is_shutdown.clear()
def main(): parser = argparse.ArgumentParser( description='King Phisher Interactive Database Console', conflict_handler='resolve') utilities.argp_add_args(parser) config_group = parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-c', '--config', dest='server_config', help='the server configuration file') config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url') arguments = parser.parse_args() if arguments.database_url: database_connection_url = arguments.database_url elif arguments.server_config: server_config = configuration.ex_load_config(arguments.server_config) database_connection_url = server_config.get('server.database') else: raise RuntimeError('no database connection was specified') engine = manager.init_database(database_connection_url) session = manager.Session() username = getpass.getuser() user = session.query(models.User).filter_by(name=username).first() if user is None: print("[-] no user {0} found in the database".format(username)) return rpc_session = aaa.AuthenticatedSession(user=user) console = code.InteractiveConsole( dict(engine=engine, graphql_query=graphql_query, manager=manager, models=models, pprint=pprint.pprint, rpc_session=rpc_session, session=session)) console.interact('starting interactive database console') if os.path.isdir(os.path.dirname(history_file)): readline.write_history_file(history_file)
def main(): parser = argparse.ArgumentParser(description='King Phisher Interactive Database Console', conflict_handler='resolve') utilities.argp_add_args(parser) config_group = parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-c', '--config', dest='server_config', type=argparse.FileType('r'), help='the server configuration file') config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url') arguments = parser.parse_args() utilities.configure_stream_logger(arguments.loglvl, arguments.logger) if arguments.database_url: database_connection_url = arguments.database_url elif arguments.server_config: server_config = yaml.load(arguments.server_config) database_connection_url = server_config['server']['database'] else: raise RuntimeError('no database connection was specified') engine = manager.init_database(database_connection_url) session = manager.Session() console = code.InteractiveConsole(dict(engine=engine, manager=manager, models=models, session=session)) console.interact('starting interactive database console')
def __init__(self, config, *args, **kwargs): """ :param config: Configuration to retrieve settings from. :type config: :py:class:`.Configuration` """ self.logger = logging.getLogger('KingPhisher.Server') super(KingPhisherServer, self).__init__(*args, **kwargs) self.config = config """The main King Phisher server configuration.""" self.serve_files = True self.serve_files_root = config.get('server.web_root') self.serve_files_list_directories = False self.serve_robots_txt = True self.database_engine = db_manager.init_database( config.get('server.database')) self.http_server.config = config self.http_server.throttle_semaphore = threading.Semaphore() self.http_server.forked_authenticator = authenticator.ForkedAuthenticator( ) self.logger.debug('forked an authenticating process with PID: ' + str(self.http_server.forked_authenticator.child_pid)) self.job_manager = job.JobManager() """A :py:class:`.JobManager` instance for scheduling tasks.""" self.job_manager.start() self.http_server.job_manager = self.job_manager loader = jinja2.FileSystemLoader(config.get('server.web_root')) global_vars = {} if config.has_section('server.page_variables'): global_vars = config.get('server.page_variables') global_vars['make_csrf_page'] = pages.make_csrf_page global_vars['make_redirect_page'] = pages.make_redirect_page self.http_server.template_env = templates.BaseTemplateEnvironment( loader=loader, global_vars=global_vars) self.__is_shutdown = threading.Event() self.__is_shutdown.clear()
def _init_db(self): try: db_manager.init_database('sqlite://') except Exception as error: self.fail("failed to initialize the database (error: {0})".format( error.__class__.__name__))
def __init__(self, config, plugin_manager, handler_klass, *args, **kwargs): """ :param config: Configuration to retrieve settings from. :type config: :py:class:`smoke_zephyr.configuration.Configuration` """ # additional mime types to be treated as html because they're probably cloned pages handler_klass.extensions_map.update({ '': 'text/html', '.asp': 'text/html', '.aspx': 'text/html', '.cfm': 'text/html', '.cgi': 'text/html', '.do': 'text/html', '.jsp': 'text/html', '.nsf': 'text/html', '.php': 'text/html', '.srf': 'text/html' }) super(KingPhisherServer, self).__init__(handler_klass, *args, **kwargs) self.logger = logging.getLogger('KingPhisher.Server') self.config = config """A :py:class:`~smoke_zephyr.configuration.Configuration` instance used as the main King Phisher server configuration.""" self.headers = collections.OrderedDict() """A :py:class:`~collections.OrderedDict` containing additional headers specified from the server configuration to include in responses.""" self.plugin_manager = plugin_manager self.serve_files = True self.serve_files_root = config.get('server.web_root') self.serve_files_list_directories = False self.serve_robots_txt = True self.database_engine = db_manager.init_database(config.get('server.database'), extra_init=True) self.throttle_semaphore = threading.BoundedSemaphore() self.session_manager = aaa.AuthenticatedSessionManager( timeout=config.get_if_exists('server.authentication.session_timeout', '30m') ) self.forked_authenticator = aaa.ForkedAuthenticator( cache_timeout=config.get_if_exists('server.authentication.cache_timeout', '10m'), required_group=config.get_if_exists('server.authentication.group'), pam_service=config.get_if_exists('server.authentication.pam_service', 'sshd') ) self.job_manager = smoke_zephyr.job.JobManager(logger_name='KingPhisher.Server.JobManager') """A :py:class:`~smoke_zephyr.job.JobManager` instance for scheduling tasks.""" self.job_manager.start() maintenance_interval = 900 # 15 minutes self._maintenance_job = self.job_manager.job_add(self._maintenance, parameters=(maintenance_interval,), seconds=maintenance_interval) loader = jinja2.FileSystemLoader(config.get('server.web_root')) global_vars = {} if config.has_section('server.page_variables'): global_vars = config.get('server.page_variables') global_vars.update(template_extras.functions) self.template_env = templates.TemplateEnvironmentBase(loader=loader, global_vars=global_vars) self.ws_manager = web_sockets.WebSocketsManager(config, self.job_manager) self.tables_api = {} self._init_tables_api() for http_server in self.sub_servers: http_server.add_sni_cert = self.add_sni_cert http_server.config = config http_server.forked_authenticator = self.forked_authenticator http_server.get_sni_certs = lambda: self.sni_certs http_server.headers = self.headers http_server.job_manager = self.job_manager http_server.kp_shutdown = self.shutdown http_server.plugin_manager = plugin_manager http_server.remove_sni_cert = self.remove_sni_cert http_server.session_manager = self.session_manager http_server.tables_api = self.tables_api http_server.template_env = self.template_env http_server.throttle_semaphore = self.throttle_semaphore http_server.ws_manager = self.ws_manager if not config.has_option('server.secret_id'): test_id = rest_api.generate_token() config.set('server.secret_id', test_id) self.logger.debug('server request test id initialized with value: ' + test_id) if not config.get_if_exists('server.rest_api.token'): config.set('server.rest_api.token', rest_api.generate_token()) if config.get('server.rest_api.enabled'): self.logger.info('rest api token initialized with value: ' + config.get('server.rest_api.token')) self.__geoip_db = geoip.init_database(config.get('server.geoip.database')) self.__is_shutdown = threading.Event() self.__is_shutdown.clear() self.__shutdown_lock = threading.Lock() plugin_manager.server = weakref.proxy(self) headers = self.config.get_if_exists('server.headers', []) for header in headers: if ': ' not in header: self.logger.warning("header '{0}' is invalid and will not be included".format(header)) continue header, value = header.split(': ', 1) header = header.strip() self.headers[header] = value self.logger.info("including {0} custom http headers".format(len(self.headers)))
def main(): parser = argparse.ArgumentParser( conflict_handler='resolve', description=PARSER_DESCRIPTION, epilog=PARSER_EPILOG, formatter_class=argparse.RawTextHelpFormatter) utilities.argp_add_args(parser) config_group = parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-c', '--config', dest='server_config', help='the server configuration file') config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url') parser.add_argument('--force', dest='force', action='store_true', default=False, help='create the user if necessary') parser.add_argument('--otp', dest='otp_secret', help='a specific otp secret') if has_qrcode: parser.add_argument('--qrcode', dest='qrcode_filename', help='generate a qrcode image file') parser.add_argument('user', help='the user to mange') parser.add_argument('action', choices=('remove', 'set', 'show'), help='the action to preform') parser.epilog = PARSER_EPILOG arguments = parser.parse_args() if arguments.database_url: database_connection_url = arguments.database_url elif arguments.server_config: server_config = configuration.ex_load_config(arguments.server_config) database_connection_url = server_config.get('server.database') else: raise RuntimeError('no database connection was specified') manager.init_database(database_connection_url) session = manager.Session() user = session.query(models.User).filter_by(name=arguments.user).first() if not user: if not arguments.force: color.print_error("invalid user id: {0}".format(arguments.user)) return user = models.User(name=arguments.user) session.add(user) color.print_status('the specified user was created') for case in utilities.switch(arguments.action): if case('remove'): user.otp_secret = None break if case('set'): if user.otp_secret: color.print_error( "the specified user already has an otp secret set") return if arguments.otp_secret: new_otp = arguments.otp_secret else: new_otp = pyotp.random_base32() if len(new_otp) != 16: color.print_error("invalid otp secret length, must be 16") return user.otp_secret = new_otp break if user.otp_secret: color.print_status("user: {0} otp: {1}".format(user.name, user.otp_secret)) totp = pyotp.TOTP(user.otp_secret) uri = totp.provisioning_uri(user.name + '@king-phisher') + '&issuer=King%20Phisher' color.print_status("provisioning uri: {0}".format(uri)) if has_qrcode and arguments.qrcode_filename: img = qrcode.make(uri) img.save(arguments.qrcode_filename) color.print_status("wrote qrcode image to: " + arguments.qrcode_filename) else: color.print_status("user: {0} otp: N/A".format(user.id)) session.commit()
def __init__(self, config, plugin_manager, handler_klass, *args, **kwargs): """ :param config: Configuration to retrieve settings from. :type config: :py:class:`smoke_zephyr.configuration.Configuration` """ # additional mime types to be treated as html because they're probably cloned pages handler_klass.extensions_map.update({ '': 'text/html', '.asp': 'text/html', '.aspx': 'text/html', '.cfm': 'text/html', '.cgi': 'text/html', '.do': 'text/html', '.jsp': 'text/html', '.nsf': 'text/html', '.php': 'text/html', '.srf': 'text/html' }) super(KingPhisherServer, self).__init__(handler_klass, *args, **kwargs) self.logger = logging.getLogger('KingPhisher.Server') self.config = config """A :py:class:`~smoke_zephyr.configuration.Configuration` instance used as the main King Phisher server configuration.""" self.headers = collections.OrderedDict() """A :py:class:`~collections.OrderedDict` containing additional headers specified from the server configuration to include in responses.""" self.plugin_manager = plugin_manager self.serve_files = True self.serve_files_root = config.get('server.web_root') self.serve_files_list_directories = False self.serve_robots_txt = True self.database_engine = db_manager.init_database(config.get('server.database'), extra_init=True) self.throttle_semaphore = threading.BoundedSemaphore() self.session_manager = aaa.AuthenticatedSessionManager( timeout=config.get_if_exists('server.authentication.cache_timeout', '30m') ) self.forked_authenticator = aaa.ForkedAuthenticator( cache_timeout=config.get_if_exists('server.authentication.cache_timeout', '10m'), required_group=config.get_if_exists('server.authentication.group'), pam_service=config.get_if_exists('server.authentication.pam_service', 'sshd') ) self.job_manager = smoke_zephyr.job.JobManager(logger_name='KingPhisher.Server.JobManager') """A :py:class:`~smoke_zephyr.job.JobManager` instance for scheduling tasks.""" self.job_manager.start() loader = jinja2.FileSystemLoader(config.get('server.web_root')) global_vars = {} if config.has_section('server.page_variables'): global_vars = config.get('server.page_variables') global_vars.update(pages.EXPORTED_FUNCTIONS) self.template_env = templates.TemplateEnvironmentBase(loader=loader, global_vars=global_vars) self.ws_manager = web_sockets.WebSocketsManager(config, self.job_manager) for http_server in self.sub_servers: http_server.config = config http_server.plugin_manager = plugin_manager http_server.throttle_semaphore = self.throttle_semaphore http_server.session_manager = self.session_manager http_server.forked_authenticator = self.forked_authenticator http_server.job_manager = self.job_manager http_server.template_env = self.template_env http_server.kp_shutdown = self.shutdown http_server.ws_manager = self.ws_manager http_server.headers = self.headers if not config.has_option('server.secret_id'): config.set('server.secret_id', rest_api.generate_token()) if not config.get_if_exists('server.rest_api.token'): config.set('server.rest_api.token', rest_api.generate_token()) if config.get('server.rest_api.enabled'): self.logger.info('rest api initialized with token: ' + config.get('server.rest_api.token')) self.__geoip_db = geoip.init_database(config.get('server.geoip.database')) self.__is_shutdown = threading.Event() self.__is_shutdown.clear() self.__shutdown_lock = threading.Lock() plugin_manager.server = weakref.proxy(self) headers = self.config.get_if_exists('server.headers', []) for header in headers: if ': ' not in header: self.logger.warning("header '{0}' is invalid and will not be included".format(header)) continue header, value = header.split(': ', 1) header = header.strip() self.headers[header] = value self.logger.info("including {0} custom http headers".format(len(self.headers)))
def __init__(self, config, plugin_manager, handler_klass, *args, **kwargs): """ :param config: Configuration to retrieve settings from. :type config: :py:class:`smoke_zephyr.configuration.Configuration` """ # additional mime types to be treated as html because they're probably cloned pages handler_klass.extensions_map.update({ '': 'text/html', '.asp': 'text/html', '.aspx': 'text/html', '.cfm': 'text/html', '.cgi': 'text/html', '.do': 'text/html', '.jsp': 'text/html', '.nsf': 'text/html', '.php': 'text/html', '.srf': 'text/html' }) super(KingPhisherServer, self).__init__(handler_klass, *args, **kwargs) self.logger = logging.getLogger('KingPhisher.Server') self.config = config """A :py:class:`~smoke_zephyr.configuration.Configuration` instance used as the main King Phisher server configuration.""" self.plugin_manager = plugin_manager self.serve_files = True self.serve_files_root = config.get('server.web_root') self.serve_files_list_directories = False self.serve_robots_txt = True self.database_engine = db_manager.init_database(config.get('server.database'), extra_init=True) self.throttle_semaphore = threading.Semaphore() self.session_manager = aaa.AuthenticatedSessionManager( timeout=config.get_if_exists('server.authentication.cache_timeout', '30m') ) self.forked_authenticator = aaa.ForkedAuthenticator( cache_timeout=config.get_if_exists('server.authentication.cache_timeout', '10m'), required_group=config.get_if_exists('server.authentication.group'), pam_service=config.get_if_exists('server.authentication.pam_service', 'sshd') ) self.job_manager = job.JobManager() """A :py:class:`~smoke_zephyr.job.JobManager` instance for scheduling tasks.""" self.job_manager.start() loader = jinja2.FileSystemLoader(config.get('server.web_root')) global_vars = {} if config.has_section('server.page_variables'): global_vars = config.get('server.page_variables') global_vars['embed_youtube_video'] = pages.embed_youtube_video global_vars['make_csrf_page'] = pages.make_csrf_page global_vars['make_redirect_page'] = pages.make_redirect_page self.template_env = templates.TemplateEnvironmentBase(loader=loader, global_vars=global_vars) for http_server in self.sub_servers: http_server.config = config http_server.plugin_manager = plugin_manager http_server.throttle_semaphore = self.throttle_semaphore http_server.session_manager = self.session_manager http_server.forked_authenticator = self.forked_authenticator http_server.job_manager = self.job_manager http_server.template_env = self.template_env http_server.kp_shutdown = self.shutdown if not config.has_option('server.secret_id'): config.set('server.secret_id', rest_api.generate_token()) if not config.get_if_exists('server.rest_api.token'): config.set('server.rest_api.token', rest_api.generate_token()) if config.get('server.rest_api.enabled'): self.logger.info('rest api initialized with token: ' + config.get('server.rest_api.token')) self.__geoip_db = geoip.init_database(config.get('server.geoip.database')) self.__is_shutdown = threading.Event() self.__is_shutdown.clear() self.__shutdown_lock = threading.Lock() plugin_manager.server = self
def main(): parser = argparse.ArgumentParser(description='King Phisher TOTP Enrollment Utility', conflict_handler='resolve') utilities.argp_add_args(parser) config_group = parser.add_mutually_exclusive_group(required=True) config_group.add_argument('-c', '--config', dest='server_config', help='the server configuration file') config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url') parser.add_argument('--force', dest='force', action='store_true', default=False, help='create the user if necessary') parser.add_argument('--otp', dest='otp_secret', help='a specific otp secret') if has_qrcode: parser.add_argument('--qrcode', dest='qrcode_filename', help='generate a qrcode image file') parser.add_argument('user', help='the user to mange') parser.add_argument('action', choices=('remove', 'set', 'show'), help='the action to preform') parser.epilog = PARSER_EPILOG arguments = parser.parse_args() if arguments.database_url: database_connection_url = arguments.database_url elif arguments.server_config: server_config = configuration.ex_load_config(arguments.server_config) database_connection_url = server_config.get('server.database') else: raise RuntimeError('no database connection was specified') manager.init_database(database_connection_url) session = manager.Session() user = session.query(models.User).filter_by(name=arguments.user).first() if not user: if not arguments.force: color.print_error("invalid user id: {0}".format(arguments.user)) return user = models.User(name=arguments.user) session.add(user) color.print_status('the specified user was created') for case in utilities.switch(arguments.action): if case('remove'): user.otp_secret = None break if case('set'): if user.otp_secret: color.print_error("the specified user already has an otp secret set") return if arguments.otp_secret: new_otp = arguments.otp_secret else: new_otp = pyotp.random_base32() if len(new_otp) != 16: color.print_error("invalid otp secret length, must be 16") return user.otp_secret = new_otp break if user.otp_secret: color.print_status("user: {0} otp: {1}".format(user.name, user.otp_secret)) totp = pyotp.TOTP(user.otp_secret) uri = totp.provisioning_uri(user.name + '@king-phisher') + '&issuer=King%20Phisher' color.print_status("provisioning uri: {0}".format(uri)) if has_qrcode and arguments.qrcode_filename: img = qrcode.make(uri) img.save(arguments.qrcode_filename) color.print_status("wrote qrcode image to: " + arguments.qrcode_filename) else: color.print_status("user: {0} otp: N/A".format(user.id)) session.commit()
def _init_db(self): try: db_manager.init_database('sqlite://') except Exception as error: self.fail("failed to initialize the database (error: {0})".format(error.__class__.__name__))