Ejemplo n.º 1
0
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()
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
	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()
Ejemplo n.º 4
0
	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()
Ejemplo n.º 5
0
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)
Ejemplo n.º 7
0
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')
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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()
Ejemplo n.º 11
0
    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()
Ejemplo n.º 12
0
	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()
Ejemplo n.º 13
0
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)
Ejemplo n.º 14
0
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')
Ejemplo n.º 15
0
    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()
Ejemplo n.º 16
0
 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__))
Ejemplo n.º 17
0
	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)))
Ejemplo n.º 18
0
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()
Ejemplo n.º 19
0
	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)))
Ejemplo n.º 20
0
	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
Ejemplo n.º 21
0
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__))