Exemple #1
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()
 def initialize(self):
     signals.campaign_alert.connect(self.on_campaign_alert)
     signals.campaign_alert_expired.connect(self.on_campaign_alert_expired)
     template_path = self.config['email_jinja_template']
     if not template_path:
         template_path = os.path.join(
             os.path.dirname(os.path.realpath(__file__)), 'template.html')
     if not os.path.isfile(template_path):
         self.logger.warning('invalid email template: ' + template_path)
         return False
     with open(template_path, 'r') as file_:
         template_data = file_.read()
     self.render_template = templates.TemplateEnvironmentBase().from_string(
         template_data)
     return True
Exemple #3
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)))
Exemple #4
0
class WebKitHTMLView(_WebKitX_WebView):
    """
	A WebView widget with additional convenience methods for rendering simple
	HTML content from either files or strings. If a link is opened within the
	document, the webview will emit the 'open-uri' signal instead of navigating
	to it.
	"""
    __gsignals__ = {
        'open-remote-uri':
        (GObject.SIGNAL_RUN_FIRST, None,
         (str, (WebKitX.NavigationPolicyDecision
                if has_webkit2 else WebKitX.WebPolicyDecision)))
    }
    template_env = templates.TemplateEnvironmentBase(
        loader=templates.FindFileSystemLoader())
    """
	The :py:class:`~king_phisher.templates.TemplateEnvironmentBase` instance to
	use when rendering template content. The environment uses the
	:py:class:`~king_phisher.templates.FindFileSystemLoader` loader.
	"""
    def __init__(self):
        super(WebKitHTMLView, self).__init__()
        self.logger = logging.getLogger('KingPhisher.Client.' +
                                        self.__class__.__name__)

        if has_webkit2:
            self.get_context().set_cache_model(
                WebKitX.CacheModel.DOCUMENT_VIEWER)
            self.connect('decide-policy', self.signal_decide_policy)
        else:
            self.connect('navigation-policy-decision-requested',
                         self.signal_decide_policy_webkit)

        self.connect('button-press-event', self.signal_button_pressed)

    def do_open_remote_uri(self, uri, decision):
        self.logger.debug('received request to open uri: ' + uri)

    def load_html_data(self, html_data, html_file_uri=None):
        """
		Load arbitrary HTML data into the WebKit engine to be rendered.

		:param str html_data: The HTML data to load into WebKit.
		:param str html_file_uri: The URI of the file where the HTML data came from.
		"""
        if isinstance(html_file_uri,
                      str) and not html_file_uri.startswith('file://'):
            html_file_uri = 'file://' + html_file_uri

        if has_webkit2:
            self.load_html(html_data, html_file_uri)
        else:
            if html_file_uri is None:
                html_file_uri = 'file://' + os.getcwd()
            self.load_string(html_data, 'text/html', 'UTF-8', html_file_uri)

    def load_html_file(self, html_file):
        """
		Load arbitrary HTML data from a file into the WebKit engine to be
		rendered.

		:param str html_file: The path to the file to load HTML data from.
		"""
        with codecs.open(html_file, 'r', encoding='utf-8') as file_h:
            html_data = file_h.read()
        self.load_html_data(html_data, html_file)

    def load_markdown_data(self,
                           md_data,
                           html_file_uri=None,
                           gh_flavor=True,
                           template=None,
                           template_vars=None):
        """
		Load markdown data, render it into HTML and then load it in to the
		WebKit engine. When *gh_flavor* is enabled, the markdown data is
		rendered using partial GitHub flavor support as provided by
		:py:class:`~mdx_partial_gfm.PartialGithubFlavoredMarkdownExtension`. If
		*template* is specified, it is used to load a Jinja2 template using
		:py:attr:`.template_env` into which the markdown data is passed in the
		variable ``markdown`` along with any others specified in the
		*template_vars* dictionary.

		:param str md_data: The markdown data to render into HTML for displaying.
		:param str html_file_uri: The URI of the file where the HTML data came from.
		:param bool gh_flavor: Whether or not to enable partial GitHub markdown syntax support.
		:param str template: The name of a Jinja2 HTML template to load for hosting the rendered markdown.
		:param template_vars: Additional variables to pass to the Jinja2 :py:class:`~jinja2.Template` when rendering it.
		:return:
		"""
        extensions = []
        if gh_flavor:
            extensions = [
                mdx_partial_gfm.PartialGithubFlavoredMarkdownExtension()
            ]
        md_data = markdown.markdown(md_data, extensions=extensions)
        if template:
            template = self.template_env.get_template(template)
            template_vars = template_vars or {}
            template_vars['markdown'] = jinja2.Markup(md_data)
            html = template.render(template_vars)
        else:
            html = md_data
        return self.load_html_data(html, html_file_uri=html_file_uri)

    def load_markdown_file(self, md_file, **kwargs):
        """
		Load markdown data from a file and render it using
		:py:meth:`~.load_markdown_data`.

		:param str md_file: The path to the file to load markdown data from.
		:param kwargs: Additional keyword arguments to pass to :py:meth:`~.load_markdown_data`.
		"""
        with codecs.open(md_file, 'r', encoding='utf-8') as file_h:
            md_data = file_h.read()
        return self.load_markdown_data(md_data, md_file, **kwargs)

    def signal_button_pressed(self, _, event):
        if event.button == Gdk.BUTTON_SECONDARY:
            # disable right click altogether
            return True

    # webkit2 signal handler
    def signal_decide_policy(self, _, decision, decision_type):
        if decision_type == WebKitX.PolicyDecisionType.NAVIGATION_ACTION:
            uri_request = decision.get_request()
            uri = uri_request.get_uri()
            if uri.startswith('file:'):
                decision.use()
            else:
                decision.ignore()
                self.emit('open-remote-uri', uri, decision)

    # webkit signal handler
    def signal_decide_policy_webkit(self, view, frame, request, action,
                                    policy):
        uri = request.get_uri()
        if uri.startswith('file://'):
            policy.use()
        else:
            policy.ignore()
            self.emit('open-remote-uri', uri, policy)